/*-------------------------------------------------------------------------
 *
 * equalfuncs.c
 *	  比较节点树的相等性函数。
 *
 * 注意：我们当前支持比较解析树中发现的所有节点类型。
 * 我们不支持比较执行器状态树；没有必要这样做，也没有必要维护
 * 所有需要的代码。我们也不支持比较 Path 树，主要是因为  
 * RelOptInfo 和 Path 节点之间的循环链接无法在简单的深度优先
 * 遍历中轻松处理。
 *
 * 事实上，当前 equal() 也不知道如何比较计划树。这可能在某
 * 天需要修复。
 *
 * 注意：有意不比较位置字段（在具有此字段的节点中）。这是因为
 * 我们希望，例如，将变量“x”视为等同于查询中对“x”的另一个
 * 引用。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  src/backend/nodes/equalfuncs.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "miscadmin.h"
#include "nodes/extensible.h"
#include "nodes/pathnodes.h"
#include "utils/datum.h"


/*
 * 宏用于简化不同类型字段的比较。尽可能使用这些宏以减少愚蠢拼写错误的机会。请注意，这些宏硬编码了Equal例程中局部变量的命名为'a'和'b'的约定。
 */

/* 比较简单的标量字段（int、float、bool、enum等） */
#define COMPARE_SCALAR_FIELD(fldname) \
	do { \
		if (fc_a->fldname != fc_b->fldname) \
			return false; \
	} while (0)

/* 比较一个指向某种节点或节点树的指针字段 */
#define COMPARE_NODE_FIELD(fldname) \
	do { \
		if (!equal(fc_a->fldname, fc_b->fldname)) \
			return false; \
	} while (0)

/* 比较一个指向Bitmapset的指针字段 */
#define COMPARE_BITMAPSET_FIELD(fldname) \
	do { \
		if (!bms_equal(fc_a->fldname, fc_b->fldname)) \
			return false; \
	} while (0)

/* 比较一个指向C字符串的指针字段，或者NULL */
#define COMPARE_STRING_FIELD(fldname) \
	do { \
		if (!equalstr(fc_a->fldname, fc_b->fldname)) \
			return false; \
	} while (0)

/* 用于比较可能为NULL的字符串字段的宏 */
#define equalstr(a, b)	\
	(((a) != NULL && (b) != NULL) ? (strcmp(a, b) == 0) : (a) == (b))

/* 比较一个内联数组的字段 */
#define COMPARE_ARRAY_FIELD(fldname) \
	do { \
		if (memcmp(a->fldname, b->fldname, sizeof(a->fldname)) != 0) \
			return false; \
	} while (0)

/* 比较一个指向简单palloc'd对象的指针字段，大小为sz */
#define COMPARE_POINTER_FIELD(fldname, sz) \
	do { \
		if (memcmp(fc_a->fldname, fc_b->fldname, (sz)) != 0) \
			return false; \
	} while (0)

/* 比较一个解析位置字段（如上所述，这是一个无操作） */
#define COMPARE_LOCATION_FIELD(fldname) \
	((void) 0)

/* 比较一个CoercionForm字段（同样是无操作，根据primnodes.h中的注释） */
#define COMPARE_COERCIONFORM_FIELD(fldname) \
	((void) 0)


/*
 * 来自primnodes.h的内容
 */

static bool fc__equalAlias(const Alias *fc_a, const Alias *fc_b)
{
	COMPARE_STRING_FIELD(aliasname);
	COMPARE_NODE_FIELD(colnames);

	return true;
}

static bool fc__equalRangeVar(const RangeVar *fc_a, const RangeVar *fc_b)
{
	COMPARE_STRING_FIELD(catalogname);
	COMPARE_STRING_FIELD(schemaname);
	COMPARE_STRING_FIELD(relname);
	COMPARE_SCALAR_FIELD(inh);
	COMPARE_SCALAR_FIELD(relpersistence);
	COMPARE_NODE_FIELD(alias);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalTableFunc(const TableFunc *fc_a, const TableFunc *fc_b)
{
	COMPARE_NODE_FIELD(ns_uris);
	COMPARE_NODE_FIELD(ns_names);
	COMPARE_NODE_FIELD(docexpr);
	COMPARE_NODE_FIELD(rowexpr);
	COMPARE_NODE_FIELD(colnames);
	COMPARE_NODE_FIELD(coltypes);
	COMPARE_NODE_FIELD(coltypmods);
	COMPARE_NODE_FIELD(colcollations);
	COMPARE_NODE_FIELD(colexprs);
	COMPARE_NODE_FIELD(coldefexprs);
	COMPARE_BITMAPSET_FIELD(notnulls);
	COMPARE_SCALAR_FIELD(ordinalitycol);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalIntoClause(const IntoClause *fc_a, const IntoClause *fc_b)
{
	COMPARE_NODE_FIELD(rel);
	COMPARE_NODE_FIELD(colNames);
	COMPARE_STRING_FIELD(accessMethod);
	COMPARE_NODE_FIELD(options);
	COMPARE_SCALAR_FIELD(onCommit);
	COMPARE_STRING_FIELD(tableSpaceName);
	COMPARE_NODE_FIELD(viewQuery);
	COMPARE_SCALAR_FIELD(skipData);

	return true;
}

/*
 * 我们不需要一个_equalExpr，因为Expr是一个抽象超类型，不应该被实例化。此外，由于除了NodeTag外没有公共字段，因此没有必要有一个辅助例程来提取比较公共字段...
 */

static bool fc__equalVar(const Var *fc_a, const Var *fc_b)
{
	COMPARE_SCALAR_FIELD(varno);
	COMPARE_SCALAR_FIELD(varattno);
	COMPARE_SCALAR_FIELD(vartype);
	COMPARE_SCALAR_FIELD(vartypmod);
	COMPARE_SCALAR_FIELD(varcollid);
	COMPARE_SCALAR_FIELD(varlevelsup);

	/*
	 * varnosyn/varattnosyn在这里被故意忽略，因为具有不同语法标识符的Vars在语义上是相同的，只要它们的varno/varattno匹配。
	 */
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalConst(const Const *fc_a, const Const *fc_b)
{
	COMPARE_SCALAR_FIELD(consttype);
	COMPARE_SCALAR_FIELD(consttypmod);
	COMPARE_SCALAR_FIELD(constcollid);
	COMPARE_SCALAR_FIELD(constlen);
	COMPARE_SCALAR_FIELD(constisnull);
	COMPARE_SCALAR_FIELD(constbyval);
	COMPARE_LOCATION_FIELD(location);

	/*
	 * 我们将所有相同类型的NULL常量视为相等。将来这可能需要更改？但datumIsEqual对NULL无效，因此...
	 */
	if (fc_a->constisnull)
		return true;
	return datumIsEqual(fc_a->constvalue, fc_b->constvalue,
						fc_a->constbyval, fc_a->constlen);
}

static bool fc__equalParam(const Param *fc_a, const Param *fc_b)
{
	COMPARE_SCALAR_FIELD(paramkind);
	COMPARE_SCALAR_FIELD(paramid);
	COMPARE_SCALAR_FIELD(paramtype);
	COMPARE_SCALAR_FIELD(paramtypmod);
	COMPARE_SCALAR_FIELD(paramcollid);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalAggref(const Aggref *fc_a, const Aggref *fc_b)
{
	COMPARE_SCALAR_FIELD(aggfnoid);
	COMPARE_SCALAR_FIELD(aggtype);
	COMPARE_SCALAR_FIELD(aggcollid);
	COMPARE_SCALAR_FIELD(inputcollid);
	/* 忽略aggtranstype因为它可能还没有设置 */
	COMPARE_NODE_FIELD(aggargtypes);
	COMPARE_NODE_FIELD(aggdirectargs);
	COMPARE_NODE_FIELD(args);
	COMPARE_NODE_FIELD(aggorder);
	COMPARE_NODE_FIELD(aggdistinct);
	COMPARE_NODE_FIELD(aggfilter);
	COMPARE_SCALAR_FIELD(aggstar);
	COMPARE_SCALAR_FIELD(aggvariadic);
	COMPARE_SCALAR_FIELD(aggkind);
	COMPARE_SCALAR_FIELD(agglevelsup);
	COMPARE_SCALAR_FIELD(aggsplit);
	COMPARE_SCALAR_FIELD(aggno);
	COMPARE_SCALAR_FIELD(aggtransno);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalGroupingFunc(const GroupingFunc *fc_a, const GroupingFunc *fc_b)
{
	COMPARE_NODE_FIELD(args);

	/*
	 * 我们不能比较refs或cols字段
	 */

	COMPARE_SCALAR_FIELD(agglevelsup);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalWindowFunc(const WindowFunc *fc_a, const WindowFunc *fc_b)
{
	COMPARE_SCALAR_FIELD(winfnoid);
	COMPARE_SCALAR_FIELD(wintype);
	COMPARE_SCALAR_FIELD(wincollid);
	COMPARE_SCALAR_FIELD(inputcollid);
	COMPARE_NODE_FIELD(args);
	COMPARE_NODE_FIELD(aggfilter);
	COMPARE_SCALAR_FIELD(winref);
	COMPARE_SCALAR_FIELD(winstar);
	COMPARE_SCALAR_FIELD(winagg);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalSubscriptingRef(const SubscriptingRef *fc_a, const SubscriptingRef *fc_b)
{
	COMPARE_SCALAR_FIELD(refcontainertype);
	COMPARE_SCALAR_FIELD(refelemtype);
	COMPARE_SCALAR_FIELD(refrestype);
	COMPARE_SCALAR_FIELD(reftypmod);
	COMPARE_SCALAR_FIELD(refcollid);
	COMPARE_NODE_FIELD(refupperindexpr);
	COMPARE_NODE_FIELD(reflowerindexpr);
	COMPARE_NODE_FIELD(refexpr);
	COMPARE_NODE_FIELD(refassgnexpr);

	return true;
}

static bool fc__equalFuncExpr(const FuncExpr *fc_a, const FuncExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(funcid);
	COMPARE_SCALAR_FIELD(funcresulttype);
	COMPARE_SCALAR_FIELD(funcretset);
	COMPARE_SCALAR_FIELD(funcvariadic);
	COMPARE_COERCIONFORM_FIELD(funcformat);
	COMPARE_SCALAR_FIELD(funccollid);
	COMPARE_SCALAR_FIELD(inputcollid);
	COMPARE_NODE_FIELD(args);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalNamedArgExpr(const NamedArgExpr *fc_a, const NamedArgExpr *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_STRING_FIELD(name);
	COMPARE_SCALAR_FIELD(argnumber);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalOpExpr(const OpExpr *fc_a, const OpExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(opno);

	/*
	 * 特殊情况opfuncid：如果一个节点包含零而另一个节点不包含，则允许它们不同。这只是意味着一个节点在解析/计划管道中未达到同样的进度，并且尚未填充opfuncid缓存。
	 */
	if (fc_a->opfuncid != fc_b->opfuncid &&
		fc_a->opfuncid != 0 &&
		fc_b->opfuncid != 0)
		return false;

	COMPARE_SCALAR_FIELD(opresulttype);
	COMPARE_SCALAR_FIELD(opretset);
	COMPARE_SCALAR_FIELD(opcollid);
	COMPARE_SCALAR_FIELD(inputcollid);
	COMPARE_NODE_FIELD(args);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalDistinctExpr(const DistinctExpr *fc_a, const DistinctExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(opno);

	/*
	 * 特殊情况opfuncid：如果一个节点包含零而另一个节点不包含，则允许它们不同。这只是意味着一个节点在解析/计划管道中未达到同样的进度，并且尚未填充opfuncid缓存。
	 */
	if (fc_a->opfuncid != fc_b->opfuncid &&
		fc_a->opfuncid != 0 &&
		fc_b->opfuncid != 0)
		return false;

	COMPARE_SCALAR_FIELD(opresulttype);
	COMPARE_SCALAR_FIELD(opretset);
	COMPARE_SCALAR_FIELD(opcollid);
	COMPARE_SCALAR_FIELD(inputcollid);
	COMPARE_NODE_FIELD(args);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalNullIfExpr(const NullIfExpr *fc_a, const NullIfExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(opno);

	/*
	 * 特殊情况opfuncid：如果一个节点包含零而另一个节点不包含，则允许它们不同。这只是意味着一个节点在解析/计划管道中未达到同样的进度，并且尚未填充opfuncid缓存。
	 */
	if (fc_a->opfuncid != fc_b->opfuncid &&
		fc_a->opfuncid != 0 &&
		fc_b->opfuncid != 0)
		return false;

	COMPARE_SCALAR_FIELD(opresulttype);
	COMPARE_SCALAR_FIELD(opretset);
	COMPARE_SCALAR_FIELD(opcollid);
	COMPARE_SCALAR_FIELD(inputcollid);
	COMPARE_NODE_FIELD(args);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalScalarArrayOpExpr(const ScalarArrayOpExpr *fc_a, const ScalarArrayOpExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(opno);

	/*
	 * 特殊情况opfuncid：如果一个节点包含零而另一个节点不包含，则允许它们不同。这只是意味着一个节点在解析/计划管道中未达到同样的进度，并且尚未填充opfuncid缓存。
	 */
	if (fc_a->opfuncid != fc_b->opfuncid &&
		fc_a->opfuncid != 0 &&
		fc_b->opfuncid != 0)
		return false;

	/* 如上所述，hashfuncid也可能不同 */
	if (fc_a->hashfuncid != fc_b->hashfuncid &&
		fc_a->hashfuncid != 0 &&
		fc_b->hashfuncid != 0)
		return false;

	/* negfuncid同样适用 */
	if (fc_a->negfuncid != fc_b->negfuncid &&
		fc_a->negfuncid != 0 &&
		fc_b->negfuncid != 0)
		return false;

	COMPARE_SCALAR_FIELD(useOr);
	COMPARE_SCALAR_FIELD(inputcollid);
	COMPARE_NODE_FIELD(args);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalBoolExpr(const BoolExpr *fc_a, const BoolExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(boolop);
	COMPARE_NODE_FIELD(args);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalSubLink(const SubLink *fc_a, const SubLink *fc_b)
{
	COMPARE_SCALAR_FIELD(subLinkType);
	COMPARE_SCALAR_FIELD(subLinkId);
	COMPARE_NODE_FIELD(testexpr);
	COMPARE_NODE_FIELD(operName);
	COMPARE_NODE_FIELD(subselect);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalSubPlan(const SubPlan *fc_a, const SubPlan *fc_b)
{
	COMPARE_SCALAR_FIELD(subLinkType);
	COMPARE_NODE_FIELD(testexpr);
	COMPARE_NODE_FIELD(paramIds);
	COMPARE_SCALAR_FIELD(plan_id);
	COMPARE_STRING_FIELD(plan_name);
	COMPARE_SCALAR_FIELD(firstColType);
	COMPARE_SCALAR_FIELD(firstColTypmod);
	COMPARE_SCALAR_FIELD(firstColCollation);
	COMPARE_SCALAR_FIELD(useHashTable);
	COMPARE_SCALAR_FIELD(unknownEqFalse);
	COMPARE_SCALAR_FIELD(parallel_safe);
	COMPARE_NODE_FIELD(setParam);
	COMPARE_NODE_FIELD(parParam);
	COMPARE_NODE_FIELD(args);
	COMPARE_SCALAR_FIELD(startup_cost);
	COMPARE_SCALAR_FIELD(per_call_cost);

	return true;
}

static bool fc__equalAlternativeSubPlan(const AlternativeSubPlan *fc_a, const AlternativeSubPlan *fc_b)
{
	COMPARE_NODE_FIELD(subplans);

	return true;
}

static bool fc__equalFieldSelect(const FieldSelect *fc_a, const FieldSelect *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_SCALAR_FIELD(fieldnum);
	COMPARE_SCALAR_FIELD(resulttype);
	COMPARE_SCALAR_FIELD(resulttypmod);
	COMPARE_SCALAR_FIELD(resultcollid);

	return true;
}

static bool fc__equalFieldStore(const FieldStore *fc_a, const FieldStore *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_NODE_FIELD(newvals);
	COMPARE_NODE_FIELD(fieldnums);
	COMPARE_SCALAR_FIELD(resulttype);

	return true;
}

static bool fc__equalRelabelType(const RelabelType *fc_a, const RelabelType *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_SCALAR_FIELD(resulttype);
	COMPARE_SCALAR_FIELD(resulttypmod);
	COMPARE_SCALAR_FIELD(resultcollid);
	COMPARE_COERCIONFORM_FIELD(relabelformat);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalCoerceViaIO(const CoerceViaIO *fc_a, const CoerceViaIO *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_SCALAR_FIELD(resulttype);
	COMPARE_SCALAR_FIELD(resultcollid);
	COMPARE_COERCIONFORM_FIELD(coerceformat);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalArrayCoerceExpr(const ArrayCoerceExpr *fc_a, const ArrayCoerceExpr *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_NODE_FIELD(elemexpr);
	COMPARE_SCALAR_FIELD(resulttype);
	COMPARE_SCALAR_FIELD(resulttypmod);
	COMPARE_SCALAR_FIELD(resultcollid);
	COMPARE_COERCIONFORM_FIELD(coerceformat);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalConvertRowtypeExpr(const ConvertRowtypeExpr *fc_a, const ConvertRowtypeExpr *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_SCALAR_FIELD(resulttype);
	COMPARE_COERCIONFORM_FIELD(convertformat);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalCollateExpr(const CollateExpr *fc_a, const CollateExpr *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_SCALAR_FIELD(collOid);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalCaseExpr(const CaseExpr *fc_a, const CaseExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(casetype);
	COMPARE_SCALAR_FIELD(casecollid);
	COMPARE_NODE_FIELD(arg);
	COMPARE_NODE_FIELD(args);
	COMPARE_NODE_FIELD(defresult);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalCaseWhen(const CaseWhen *fc_a, const CaseWhen *fc_b)
{
	COMPARE_NODE_FIELD(expr);
	COMPARE_NODE_FIELD(result);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalCaseTestExpr(const CaseTestExpr *fc_a, const CaseTestExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(typeId);
	COMPARE_SCALAR_FIELD(typeMod);
	COMPARE_SCALAR_FIELD(collation);

	return true;
}

static bool fc__equalArrayExpr(const ArrayExpr *fc_a, const ArrayExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(array_typeid);
	COMPARE_SCALAR_FIELD(array_collid);
	COMPARE_SCALAR_FIELD(element_typeid);
	COMPARE_NODE_FIELD(elements);
	COMPARE_SCALAR_FIELD(multidims);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalRowExpr(const RowExpr *fc_a, const RowExpr *fc_b)
{
	COMPARE_NODE_FIELD(args);
	COMPARE_SCALAR_FIELD(row_typeid);
	COMPARE_COERCIONFORM_FIELD(row_format);
	COMPARE_NODE_FIELD(colnames);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalRowCompareExpr(const RowCompareExpr *fc_a, const RowCompareExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(rctype);
	COMPARE_NODE_FIELD(opnos);
	COMPARE_NODE_FIELD(opfamilies);
	COMPARE_NODE_FIELD(inputcollids);
	COMPARE_NODE_FIELD(largs);
	COMPARE_NODE_FIELD(rargs);

	return true;
}

static bool fc__equalCoalesceExpr(const CoalesceExpr *fc_a, const CoalesceExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(coalescetype);
	COMPARE_SCALAR_FIELD(coalescecollid);
	COMPARE_NODE_FIELD(args);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalMinMaxExpr(const MinMaxExpr *fc_a, const MinMaxExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(minmaxtype);
	COMPARE_SCALAR_FIELD(minmaxcollid);
	COMPARE_SCALAR_FIELD(inputcollid);
	COMPARE_SCALAR_FIELD(op);
	COMPARE_NODE_FIELD(args);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalSQLValueFunction(const SQLValueFunction *fc_a, const SQLValueFunction *fc_b)
{
	COMPARE_SCALAR_FIELD(op);
	COMPARE_SCALAR_FIELD(type);
	COMPARE_SCALAR_FIELD(typmod);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalXmlExpr(const XmlExpr *fc_a, const XmlExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(op);
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(named_args);
	COMPARE_NODE_FIELD(arg_names);
	COMPARE_NODE_FIELD(args);
	COMPARE_SCALAR_FIELD(xmloption);
	COMPARE_SCALAR_FIELD(type);
	COMPARE_SCALAR_FIELD(typmod);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalNullTest(const NullTest *fc_a, const NullTest *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_SCALAR_FIELD(nulltesttype);
	COMPARE_SCALAR_FIELD(argisrow);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalBooleanTest(const BooleanTest *fc_a, const BooleanTest *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_SCALAR_FIELD(booltesttype);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalCoerceToDomain(const CoerceToDomain *fc_a, const CoerceToDomain *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_SCALAR_FIELD(resulttype);
	COMPARE_SCALAR_FIELD(resulttypmod);
	COMPARE_SCALAR_FIELD(resultcollid);
	COMPARE_COERCIONFORM_FIELD(coercionformat);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalCoerceToDomainValue(const CoerceToDomainValue *fc_a, const CoerceToDomainValue *fc_b)
{
	COMPARE_SCALAR_FIELD(typeId);
	COMPARE_SCALAR_FIELD(typeMod);
	COMPARE_SCALAR_FIELD(collation);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalSetToDefault(const SetToDefault *fc_a, const SetToDefault *fc_b)
{
	COMPARE_SCALAR_FIELD(typeId);
	COMPARE_SCALAR_FIELD(typeMod);
	COMPARE_SCALAR_FIELD(collation);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalCurrentOfExpr(const CurrentOfExpr *fc_a, const CurrentOfExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(cvarno);
	COMPARE_STRING_FIELD(cursor_name);
	COMPARE_SCALAR_FIELD(cursor_param);

	return true;
}

static bool fc__equalNextValueExpr(const NextValueExpr *fc_a, const NextValueExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(seqid);
	COMPARE_SCALAR_FIELD(typeId);

	return true;
}

static bool fc__equalInferenceElem(const InferenceElem *fc_a, const InferenceElem *fc_b)
{
	COMPARE_NODE_FIELD(expr);
	COMPARE_SCALAR_FIELD(infercollid);
	COMPARE_SCALAR_FIELD(inferopclass);

	return true;
}

static bool fc__equalTargetEntry(const TargetEntry *fc_a, const TargetEntry *fc_b)
{
	COMPARE_NODE_FIELD(expr);
	COMPARE_SCALAR_FIELD(resno);
	COMPARE_STRING_FIELD(resname);
	COMPARE_SCALAR_FIELD(ressortgroupref);
	COMPARE_SCALAR_FIELD(resorigtbl);
	COMPARE_SCALAR_FIELD(resorigcol);
	COMPARE_SCALAR_FIELD(resjunk);

	return true;
}

static bool fc__equalRangeTblRef(const RangeTblRef *fc_a, const RangeTblRef *fc_b)
{
	COMPARE_SCALAR_FIELD(rtindex);

	return true;
}

static bool fc__equalJoinExpr(const JoinExpr *fc_a, const JoinExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(jointype);
	COMPARE_SCALAR_FIELD(isNatural);
	COMPARE_NODE_FIELD(larg);
	COMPARE_NODE_FIELD(rarg);
	COMPARE_NODE_FIELD(usingClause);
	COMPARE_NODE_FIELD(join_using_alias);
	COMPARE_NODE_FIELD(quals);
	COMPARE_NODE_FIELD(alias);
	COMPARE_SCALAR_FIELD(rtindex);

	return true;
}

static bool fc__equalFromExpr(const FromExpr *fc_a, const FromExpr *fc_b)
{
	COMPARE_NODE_FIELD(fromlist);
	COMPARE_NODE_FIELD(quals);

	return true;
}

static bool fc__equalOnConflictExpr(const OnConflictExpr *fc_a, const OnConflictExpr *fc_b)
{
	COMPARE_SCALAR_FIELD(action);
	COMPARE_NODE_FIELD(arbiterElems);
	COMPARE_NODE_FIELD(arbiterWhere);
	COMPARE_SCALAR_FIELD(constraint);
	COMPARE_NODE_FIELD(onConflictSet);
	COMPARE_NODE_FIELD(onConflictWhere);
	COMPARE_SCALAR_FIELD(exclRelIndex);
	COMPARE_NODE_FIELD(exclRelTlist);

	return true;
}

/*
 * 来自pathnodes.h的内容
 */

static bool fc__equalPathKey(const PathKey *fc_a, const PathKey *fc_b)
{
	/* 我们假设指针相等性足以比较eclasses */
	COMPARE_SCALAR_FIELD(pk_eclass);
	COMPARE_SCALAR_FIELD(pk_opfamily);
	COMPARE_SCALAR_FIELD(pk_strategy);
	COMPARE_SCALAR_FIELD(pk_nulls_first);

	return true;
}

static bool fc__equalRestrictInfo(const RestrictInfo *fc_a, const RestrictInfo *fc_b)
{
	COMPARE_NODE_FIELD(clause);
	COMPARE_SCALAR_FIELD(is_pushed_down);
	COMPARE_SCALAR_FIELD(outerjoin_delayed);
	COMPARE_SCALAR_FIELD(security_level);
	COMPARE_BITMAPSET_FIELD(required_relids);
	COMPARE_BITMAPSET_FIELD(outer_relids);
	COMPARE_BITMAPSET_FIELD(nullable_relids);

	/*
	 * 我们忽略所有剩余字段，因为它们可能尚未设置，并且
	 * 应该可以从条款中推导出来。
	 */

	return true;
}

static bool fc__equalPlaceHolderVar(const PlaceHolderVar *fc_a, const PlaceHolderVar *fc_b)
{
	/*
	 * 我们故意不比较 phexpr。两个具有相同 ID 和 levelsup 的
	 * PlaceHolderVars 应被视为相等，即使其中的表达式已成功
	 * 变更为不同的状态。这将在最终计划构建时发生，当存在嵌套的 PHVs，
	 * 因为在外部 PHV 的一些副本中，内部 PHV 将被 Param 替换。
	 * 它发生的另一种方式是，当进行子链接折叠时，initplan
	 * 子链接可能会被不同编号的 Params 替换。
	 * （这种情况的最终结果将是一些未引用的 initplans，
	 * 这虽然令人烦恼但其实并不算是问题。）根据同样的推理，
	 * 不需要检查 phrels。
	 *
	 * COMPARE_NODE_FIELD(phexpr);
	 *
	 * COMPARE_BITMAPSET_FIELD(phrels);
	 */
	COMPARE_SCALAR_FIELD(phid);
	COMPARE_SCALAR_FIELD(phlevelsup);

	return true;
}

static bool fc__equalSpecialJoinInfo(const SpecialJoinInfo *fc_a, const SpecialJoinInfo *fc_b)
{
	COMPARE_BITMAPSET_FIELD(min_lefthand);
	COMPARE_BITMAPSET_FIELD(min_righthand);
	COMPARE_BITMAPSET_FIELD(syn_lefthand);
	COMPARE_BITMAPSET_FIELD(syn_righthand);
	COMPARE_SCALAR_FIELD(jointype);
	COMPARE_SCALAR_FIELD(lhs_strict);
	COMPARE_SCALAR_FIELD(delay_upper_joins);
	COMPARE_SCALAR_FIELD(semi_can_btree);
	COMPARE_SCALAR_FIELD(semi_can_hash);
	COMPARE_NODE_FIELD(semi_operators);
	COMPARE_NODE_FIELD(semi_rhs_exprs);

	return true;
}

static bool fc__equalAppendRelInfo(const AppendRelInfo *fc_a, const AppendRelInfo *fc_b)
{
	COMPARE_SCALAR_FIELD(parent_relid);
	COMPARE_SCALAR_FIELD(child_relid);
	COMPARE_SCALAR_FIELD(parent_reltype);
	COMPARE_SCALAR_FIELD(child_reltype);
	COMPARE_NODE_FIELD(translated_vars);
	COMPARE_SCALAR_FIELD(num_child_cols);
	COMPARE_POINTER_FIELD(parent_colnos, fc_a->num_child_cols * sizeof(AttrNumber));
	COMPARE_SCALAR_FIELD(parent_reloid);

	return true;
}

static bool fc__equalPlaceHolderInfo(const PlaceHolderInfo *fc_a, const PlaceHolderInfo *fc_b)
{
	COMPARE_SCALAR_FIELD(phid);
	COMPARE_NODE_FIELD(ph_var); /* 应该是多余的 */
	COMPARE_BITMAPSET_FIELD(ph_eval_at);
	COMPARE_BITMAPSET_FIELD(ph_lateral);
	COMPARE_BITMAPSET_FIELD(ph_needed);
	COMPARE_SCALAR_FIELD(ph_width);

	return true;
}

/*
 * 来自 extensible.h 的内容
 */
static bool fc__equalExtensibleNode(const ExtensibleNode *fc_a, const ExtensibleNode *fc_b)
{
	const ExtensibleNodeMethods *fc_methods;

	COMPARE_STRING_FIELD(extnodename);

	/* 此时，我们知道 extnodename 在两个节点中是相同的。 */
	fc_methods = GetExtensibleNodeMethods(fc_a->extnodename, false);

	/* 比较私有字段 */
	if (!fc_methods->nodeEqual(fc_a, fc_b))
		return false;

	return true;
}

/*
 * 来自 parsenodes.h 的内容
 */

static bool fc__equalQuery(const Query *fc_a, const Query *fc_b)
{
	COMPARE_SCALAR_FIELD(commandType);
	COMPARE_SCALAR_FIELD(querySource);
	/* 我们故意忽略 queryId，因为它可能尚未设置 */
	COMPARE_SCALAR_FIELD(canSetTag);
	COMPARE_NODE_FIELD(utilityStmt);
	COMPARE_SCALAR_FIELD(resultRelation);
	COMPARE_SCALAR_FIELD(hasAggs);
	COMPARE_SCALAR_FIELD(hasWindowFuncs);
	COMPARE_SCALAR_FIELD(hasTargetSRFs);
	COMPARE_SCALAR_FIELD(hasSubLinks);
	COMPARE_SCALAR_FIELD(hasDistinctOn);
	COMPARE_SCALAR_FIELD(hasRecursive);
	COMPARE_SCALAR_FIELD(hasModifyingCTE);
	COMPARE_SCALAR_FIELD(hasForUpdate);
	COMPARE_SCALAR_FIELD(hasRowSecurity);
	COMPARE_SCALAR_FIELD(isReturn);
	COMPARE_NODE_FIELD(cteList);
	COMPARE_NODE_FIELD(rtable);
	COMPARE_NODE_FIELD(jointree);
	COMPARE_NODE_FIELD(targetList);
	COMPARE_SCALAR_FIELD(override);
	COMPARE_NODE_FIELD(onConflict);
	COMPARE_NODE_FIELD(returningList);
	COMPARE_NODE_FIELD(groupClause);
	COMPARE_SCALAR_FIELD(groupDistinct);
	COMPARE_NODE_FIELD(groupingSets);
	COMPARE_NODE_FIELD(havingQual);
	COMPARE_NODE_FIELD(windowClause);
	COMPARE_NODE_FIELD(distinctClause);
	COMPARE_NODE_FIELD(sortClause);
	COMPARE_NODE_FIELD(limitOffset);
	COMPARE_NODE_FIELD(limitCount);
	COMPARE_SCALAR_FIELD(limitOption);
	COMPARE_NODE_FIELD(rowMarks);
	COMPARE_NODE_FIELD(setOperations);
	COMPARE_NODE_FIELD(constraintDeps);
	COMPARE_NODE_FIELD(withCheckOptions);
	COMPARE_NODE_FIELD(mergeActionList);
	COMPARE_SCALAR_FIELD(mergeUseOuterJoin);
	COMPARE_LOCATION_FIELD(stmt_location);
	COMPARE_SCALAR_FIELD(stmt_len);

	return true;
}

static bool fc__equalRawStmt(const RawStmt *fc_a, const RawStmt *fc_b)
{
	COMPARE_NODE_FIELD(stmt);
	COMPARE_LOCATION_FIELD(stmt_location);
	COMPARE_SCALAR_FIELD(stmt_len);

	return true;
}

static bool fc__equalInsertStmt(const InsertStmt *fc_a, const InsertStmt *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(cols);
	COMPARE_NODE_FIELD(selectStmt);
	COMPARE_NODE_FIELD(onConflictClause);
	COMPARE_NODE_FIELD(returningList);
	COMPARE_NODE_FIELD(withClause);
	COMPARE_SCALAR_FIELD(override);

	return true;
}

static bool fc__equalDeleteStmt(const DeleteStmt *fc_a, const DeleteStmt *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(usingClause);
	COMPARE_NODE_FIELD(whereClause);
	COMPARE_NODE_FIELD(returningList);
	COMPARE_NODE_FIELD(withClause);

	return true;
}

static bool fc__equalUpdateStmt(const UpdateStmt *fc_a, const UpdateStmt *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(targetList);
	COMPARE_NODE_FIELD(whereClause);
	COMPARE_NODE_FIELD(fromClause);
	COMPARE_NODE_FIELD(returningList);
	COMPARE_NODE_FIELD(withClause);

	return true;
}

static bool fc__equalMergeStmt(const MergeStmt *fc_a, const MergeStmt *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(sourceRelation);
	COMPARE_NODE_FIELD(joinCondition);
	COMPARE_NODE_FIELD(mergeWhenClauses);
	COMPARE_NODE_FIELD(withClause);

	return true;
}

static bool fc__equalSelectStmt(const SelectStmt *fc_a, const SelectStmt *fc_b)
{
	COMPARE_NODE_FIELD(distinctClause);
	COMPARE_NODE_FIELD(intoClause);
	COMPARE_NODE_FIELD(targetList);
	COMPARE_NODE_FIELD(fromClause);
	COMPARE_NODE_FIELD(whereClause);
	COMPARE_NODE_FIELD(groupClause);
	COMPARE_SCALAR_FIELD(groupDistinct);
	COMPARE_NODE_FIELD(havingClause);
	COMPARE_NODE_FIELD(windowClause);
	COMPARE_NODE_FIELD(valuesLists);
	COMPARE_NODE_FIELD(sortClause);
	COMPARE_NODE_FIELD(limitOffset);
	COMPARE_NODE_FIELD(limitCount);
	COMPARE_SCALAR_FIELD(limitOption);
	COMPARE_NODE_FIELD(lockingClause);
	COMPARE_NODE_FIELD(withClause);
	COMPARE_SCALAR_FIELD(op);
	COMPARE_SCALAR_FIELD(all);
	COMPARE_NODE_FIELD(larg);
	COMPARE_NODE_FIELD(rarg);

	return true;
}

static bool fc__equalSetOperationStmt(const SetOperationStmt *fc_a, const SetOperationStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(op);
	COMPARE_SCALAR_FIELD(all);
	COMPARE_NODE_FIELD(larg);
	COMPARE_NODE_FIELD(rarg);
	COMPARE_NODE_FIELD(colTypes);
	COMPARE_NODE_FIELD(colTypmods);
	COMPARE_NODE_FIELD(colCollations);
	COMPARE_NODE_FIELD(groupClauses);

	return true;
}

static bool fc__equalReturnStmt(const ReturnStmt *fc_a, const ReturnStmt *fc_b)
{
	COMPARE_NODE_FIELD(returnval);

	return true;
}

static bool fc__equalPLAssignStmt(const PLAssignStmt *fc_a, const PLAssignStmt *fc_b)
{
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(indirection);
	COMPARE_SCALAR_FIELD(nnames);
	COMPARE_NODE_FIELD(val);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalAlterTableStmt(const AlterTableStmt *fc_a, const AlterTableStmt *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(cmds);
	COMPARE_SCALAR_FIELD(objtype);
	COMPARE_SCALAR_FIELD(missing_ok);

	return true;
}

static bool fc__equalAlterTableCmd(const AlterTableCmd *fc_a, const AlterTableCmd *fc_b)
{
	COMPARE_SCALAR_FIELD(subtype);
	COMPARE_STRING_FIELD(name);
	COMPARE_SCALAR_FIELD(num);
	COMPARE_NODE_FIELD(newowner);
	COMPARE_NODE_FIELD(def);
	COMPARE_SCALAR_FIELD(behavior);
	COMPARE_SCALAR_FIELD(missing_ok);
	COMPARE_SCALAR_FIELD(recurse);

	return true;
}

static bool fc__equalAlterCollationStmt(const AlterCollationStmt *fc_a, const AlterCollationStmt *fc_b)
{
	COMPARE_NODE_FIELD(collname);

	return true;
}

static bool fc__equalAlterDomainStmt(const AlterDomainStmt *fc_a, const AlterDomainStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(subtype);
	COMPARE_NODE_FIELD(typeName);
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(def);
	COMPARE_SCALAR_FIELD(behavior);
	COMPARE_SCALAR_FIELD(missing_ok);

	return true;
}

static bool fc__equalGrantStmt(const GrantStmt *fc_a, const GrantStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(is_grant);
	COMPARE_SCALAR_FIELD(targtype);
	COMPARE_SCALAR_FIELD(objtype);
	COMPARE_NODE_FIELD(objects);
	COMPARE_NODE_FIELD(privileges);
	COMPARE_NODE_FIELD(grantees);
	COMPARE_SCALAR_FIELD(grant_option);
	COMPARE_NODE_FIELD(grantor);
	COMPARE_SCALAR_FIELD(behavior);

	return true;
}

static bool fc__equalObjectWithArgs(const ObjectWithArgs *fc_a, const ObjectWithArgs *fc_b)
{
	COMPARE_NODE_FIELD(objname);
	COMPARE_NODE_FIELD(objargs);
	COMPARE_NODE_FIELD(objfuncargs);
	COMPARE_SCALAR_FIELD(args_unspecified);

	return true;
}

static bool fc__equalAccessPriv(const AccessPriv *fc_a, const AccessPriv *fc_b)
{
	COMPARE_STRING_FIELD(priv_name);
	COMPARE_NODE_FIELD(cols);

	return true;
}

static bool fc__equalGrantRoleStmt(const GrantRoleStmt *fc_a, const GrantRoleStmt *fc_b)
{
	COMPARE_NODE_FIELD(granted_roles);
	COMPARE_NODE_FIELD(grantee_roles);
	COMPARE_SCALAR_FIELD(is_grant);
	COMPARE_SCALAR_FIELD(admin_opt);
	COMPARE_NODE_FIELD(grantor);
	COMPARE_SCALAR_FIELD(behavior);

	return true;
}

static bool fc__equalAlterDefaultPrivilegesStmt(const AlterDefaultPrivilegesStmt *fc_a, const AlterDefaultPrivilegesStmt *fc_b)
{
	COMPARE_NODE_FIELD(options);
	COMPARE_NODE_FIELD(action);

	return true;
}

static bool fc__equalDeclareCursorStmt(const DeclareCursorStmt *fc_a, const DeclareCursorStmt *fc_b)
{
	COMPARE_STRING_FIELD(portalname);
	COMPARE_SCALAR_FIELD(options);
	COMPARE_NODE_FIELD(query);

	return true;
}

static bool fc__equalClosePortalStmt(const ClosePortalStmt *fc_a, const ClosePortalStmt *fc_b)
{
	COMPARE_STRING_FIELD(portalname);

	return true;
}

static bool fc__equalCallStmt(const CallStmt *fc_a, const CallStmt *fc_b)
{
	COMPARE_NODE_FIELD(funccall);
	COMPARE_NODE_FIELD(funcexpr);
	COMPARE_NODE_FIELD(outargs);

	return true;
}

static bool fc__equalClusterStmt(const ClusterStmt *fc_a, const ClusterStmt *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_STRING_FIELD(indexname);
	COMPARE_NODE_FIELD(params);

	return true;
}

static bool fc__equalCopyStmt(const CopyStmt *fc_a, const CopyStmt *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(query);
	COMPARE_NODE_FIELD(attlist);
	COMPARE_SCALAR_FIELD(is_from);
	COMPARE_SCALAR_FIELD(is_program);
	COMPARE_STRING_FIELD(filename);
	COMPARE_NODE_FIELD(options);
	COMPARE_NODE_FIELD(whereClause);

	return true;
}

static bool fc__equalCreateStmt(const CreateStmt *fc_a, const CreateStmt *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(tableElts);
	COMPARE_NODE_FIELD(inhRelations);
	COMPARE_NODE_FIELD(partbound);
	COMPARE_NODE_FIELD(partspec);
	COMPARE_NODE_FIELD(ofTypename);
	COMPARE_NODE_FIELD(constraints);
	COMPARE_NODE_FIELD(options);
	COMPARE_SCALAR_FIELD(oncommit);
	COMPARE_STRING_FIELD(tablespacename);
	COMPARE_STRING_FIELD(accessMethod);
	COMPARE_SCALAR_FIELD(if_not_exists);

	return true;
}

static bool fc__equalTableLikeClause(const TableLikeClause *fc_a, const TableLikeClause *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_SCALAR_FIELD(options);
	COMPARE_SCALAR_FIELD(relationOid);

	return true;
}

static bool fc__equalDefineStmt(const DefineStmt *fc_a, const DefineStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(kind);
	COMPARE_SCALAR_FIELD(oldstyle);
	COMPARE_NODE_FIELD(defnames);
	COMPARE_NODE_FIELD(args);
	COMPARE_NODE_FIELD(definition);
	COMPARE_SCALAR_FIELD(if_not_exists);
	COMPARE_SCALAR_FIELD(replace);

	return true;
}

static bool fc__equalDropStmt(const DropStmt *fc_a, const DropStmt *fc_b)
{
	COMPARE_NODE_FIELD(objects);
	COMPARE_SCALAR_FIELD(removeType);
	COMPARE_SCALAR_FIELD(behavior);
	COMPARE_SCALAR_FIELD(missing_ok);
	COMPARE_SCALAR_FIELD(concurrent);

	return true;
}

static bool fc__equalTruncateStmt(const TruncateStmt *fc_a, const TruncateStmt *fc_b)
{
	COMPARE_NODE_FIELD(relations);
	COMPARE_SCALAR_FIELD(restart_seqs);
	COMPARE_SCALAR_FIELD(behavior);

	return true;
}

static bool fc__equalCommentStmt(const CommentStmt *fc_a, const CommentStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(objtype);
	COMPARE_NODE_FIELD(object);
	COMPARE_STRING_FIELD(comment);

	return true;
}

static bool fc__equalSecLabelStmt(const SecLabelStmt *fc_a, const SecLabelStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(objtype);
	COMPARE_NODE_FIELD(object);
	COMPARE_STRING_FIELD(provider);
	COMPARE_STRING_FIELD(label);

	return true;
}

static bool fc__equalFetchStmt(const FetchStmt *fc_a, const FetchStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(direction);
	COMPARE_SCALAR_FIELD(howMany);
	COMPARE_STRING_FIELD(portalname);
	COMPARE_SCALAR_FIELD(ismove);

	return true;
}

static bool fc__equalIndexStmt(const IndexStmt *fc_a, const IndexStmt *fc_b)
{
	COMPARE_STRING_FIELD(idxname);
	COMPARE_NODE_FIELD(relation);
	COMPARE_STRING_FIELD(accessMethod);
	COMPARE_STRING_FIELD(tableSpace);
	COMPARE_NODE_FIELD(indexParams);
	COMPARE_NODE_FIELD(indexIncludingParams);
	COMPARE_NODE_FIELD(options);
	COMPARE_NODE_FIELD(whereClause);
	COMPARE_NODE_FIELD(excludeOpNames);
	COMPARE_STRING_FIELD(idxcomment);
	COMPARE_SCALAR_FIELD(indexOid);
	COMPARE_SCALAR_FIELD(oldNode);
	COMPARE_SCALAR_FIELD(oldCreateSubid);
	COMPARE_SCALAR_FIELD(oldFirstRelfilenodeSubid);
	COMPARE_SCALAR_FIELD(unique);
	COMPARE_SCALAR_FIELD(nulls_not_distinct);
	COMPARE_SCALAR_FIELD(primary);
	COMPARE_SCALAR_FIELD(isconstraint);
	COMPARE_SCALAR_FIELD(deferrable);
	COMPARE_SCALAR_FIELD(initdeferred);
	COMPARE_SCALAR_FIELD(transformed);
	COMPARE_SCALAR_FIELD(concurrent);
	COMPARE_SCALAR_FIELD(if_not_exists);
	COMPARE_SCALAR_FIELD(reset_default_tblspc);

	return true;
}

static bool fc__equalCreateStatsStmt(const CreateStatsStmt *fc_a, const CreateStatsStmt *fc_b)
{
	COMPARE_NODE_FIELD(defnames);
	COMPARE_NODE_FIELD(stat_types);
	COMPARE_NODE_FIELD(exprs);
	COMPARE_NODE_FIELD(relations);
	COMPARE_STRING_FIELD(stxcomment);
	COMPARE_SCALAR_FIELD(transformed);
	COMPARE_SCALAR_FIELD(if_not_exists);

	return true;
}

static bool fc__equalAlterStatsStmt(const AlterStatsStmt *fc_a, const AlterStatsStmt *fc_b)
{
	COMPARE_NODE_FIELD(defnames);
	COMPARE_SCALAR_FIELD(stxstattarget);
	COMPARE_SCALAR_FIELD(missing_ok);

	return true;
}

static bool fc__equalCreateFunctionStmt(const CreateFunctionStmt *fc_a, const CreateFunctionStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(is_procedure);
	COMPARE_SCALAR_FIELD(replace);
	COMPARE_NODE_FIELD(funcname);
	COMPARE_NODE_FIELD(parameters);
	COMPARE_NODE_FIELD(returnType);
	COMPARE_NODE_FIELD(options);
	COMPARE_NODE_FIELD(sql_body);

	return true;
}

static bool fc__equalFunctionParameter(const FunctionParameter *fc_a, const FunctionParameter *fc_b)
{
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(argType);
	COMPARE_SCALAR_FIELD(mode);
	COMPARE_NODE_FIELD(defexpr);

	return true;
}

static bool fc__equalAlterFunctionStmt(const AlterFunctionStmt *fc_a, const AlterFunctionStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(objtype);
	COMPARE_NODE_FIELD(func);
	COMPARE_NODE_FIELD(actions);

	return true;
}

static bool fc__equalDoStmt(const DoStmt *fc_a, const DoStmt *fc_b)
{
	COMPARE_NODE_FIELD(args);

	return true;
}

static bool fc__equalRenameStmt(const RenameStmt *fc_a, const RenameStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(renameType);
	COMPARE_SCALAR_FIELD(relationType);
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(object);
	COMPARE_STRING_FIELD(subname);
	COMPARE_STRING_FIELD(newname);
	COMPARE_SCALAR_FIELD(behavior);
	COMPARE_SCALAR_FIELD(missing_ok);

	return true;
}

static bool fc__equalAlterObjectDependsStmt(const AlterObjectDependsStmt *fc_a, const AlterObjectDependsStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(objectType);
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(object);
	COMPARE_NODE_FIELD(extname);
	COMPARE_SCALAR_FIELD(remove);

	return true;
}

static bool fc__equalAlterObjectSchemaStmt(const AlterObjectSchemaStmt *fc_a, const AlterObjectSchemaStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(objectType);
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(object);
	COMPARE_STRING_FIELD(newschema);
	COMPARE_SCALAR_FIELD(missing_ok);

	return true;
}

static bool fc__equalAlterOwnerStmt(const AlterOwnerStmt *fc_a, const AlterOwnerStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(objectType);
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(object);
	COMPARE_NODE_FIELD(newowner);

	return true;
}

static bool fc__equalAlterOperatorStmt(const AlterOperatorStmt *fc_a, const AlterOperatorStmt *fc_b)
{
	COMPARE_NODE_FIELD(opername);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalAlterTypeStmt(const AlterTypeStmt *fc_a, const AlterTypeStmt *fc_b)
{
	COMPARE_NODE_FIELD(typeName);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalRuleStmt(const RuleStmt *fc_a, const RuleStmt *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_STRING_FIELD(rulename);
	COMPARE_NODE_FIELD(whereClause);
	COMPARE_SCALAR_FIELD(event);
	COMPARE_SCALAR_FIELD(instead);
	COMPARE_NODE_FIELD(actions);
	COMPARE_SCALAR_FIELD(replace);

	return true;
}

static bool fc__equalNotifyStmt(const NotifyStmt *fc_a, const NotifyStmt *fc_b)
{
	COMPARE_STRING_FIELD(conditionname);
	COMPARE_STRING_FIELD(payload);

	return true;
}

static bool fc__equalListenStmt(const ListenStmt *fc_a, const ListenStmt *fc_b)
{
	COMPARE_STRING_FIELD(conditionname);

	return true;
}

static bool fc__equalUnlistenStmt(const UnlistenStmt *fc_a, const UnlistenStmt *fc_b)
{
	COMPARE_STRING_FIELD(conditionname);

	return true;
}

static bool fc__equalTransactionStmt(const TransactionStmt *fc_a, const TransactionStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(kind);
	COMPARE_NODE_FIELD(options);
	COMPARE_STRING_FIELD(savepoint_name);
	COMPARE_STRING_FIELD(gid);
	COMPARE_SCALAR_FIELD(chain);

	return true;
}

static bool fc__equalCompositeTypeStmt(const CompositeTypeStmt *fc_a, const CompositeTypeStmt *fc_b)
{
	COMPARE_NODE_FIELD(typevar);
	COMPARE_NODE_FIELD(coldeflist);

	return true;
}

static bool fc__equalCreateEnumStmt(const CreateEnumStmt *fc_a, const CreateEnumStmt *fc_b)
{
	COMPARE_NODE_FIELD(typeName);
	COMPARE_NODE_FIELD(vals);

	return true;
}

static bool fc__equalCreateRangeStmt(const CreateRangeStmt *fc_a, const CreateRangeStmt *fc_b)
{
	COMPARE_NODE_FIELD(typeName);
	COMPARE_NODE_FIELD(params);

	return true;
}

static bool fc__equalAlterEnumStmt(const AlterEnumStmt *fc_a, const AlterEnumStmt *fc_b)
{
	COMPARE_NODE_FIELD(typeName);
	COMPARE_STRING_FIELD(oldVal);
	COMPARE_STRING_FIELD(newVal);
	COMPARE_STRING_FIELD(newValNeighbor);
	COMPARE_SCALAR_FIELD(newValIsAfter);
	COMPARE_SCALAR_FIELD(skipIfNewValExists);

	return true;
}

static bool fc__equalViewStmt(const ViewStmt *fc_a, const ViewStmt *fc_b)
{
	COMPARE_NODE_FIELD(view);
	COMPARE_NODE_FIELD(aliases);
	COMPARE_NODE_FIELD(query);
	COMPARE_SCALAR_FIELD(replace);
	COMPARE_NODE_FIELD(options);
	COMPARE_SCALAR_FIELD(withCheckOption);

	return true;
}

static bool fc__equalLoadStmt(const LoadStmt *fc_a, const LoadStmt *fc_b)
{
	COMPARE_STRING_FIELD(filename);

	return true;
}

static bool fc__equalCreateDomainStmt(const CreateDomainStmt *fc_a, const CreateDomainStmt *fc_b)
{
	COMPARE_NODE_FIELD(domainname);
	COMPARE_NODE_FIELD(typeName);
	COMPARE_NODE_FIELD(collClause);
	COMPARE_NODE_FIELD(constraints);

	return true;
}

static bool fc__equalCreateOpClassStmt(const CreateOpClassStmt *fc_a, const CreateOpClassStmt *fc_b)
{
	COMPARE_NODE_FIELD(opclassname);
	COMPARE_NODE_FIELD(opfamilyname);
	COMPARE_STRING_FIELD(amname);
	COMPARE_NODE_FIELD(datatype);
	COMPARE_NODE_FIELD(items);
	COMPARE_SCALAR_FIELD(isDefault);

	return true;
}

static bool fc__equalCreateOpClassItem(const CreateOpClassItem *fc_a, const CreateOpClassItem *fc_b)
{
	COMPARE_SCALAR_FIELD(itemtype);
	COMPARE_NODE_FIELD(name);
	COMPARE_SCALAR_FIELD(number);
	COMPARE_NODE_FIELD(order_family);
	COMPARE_NODE_FIELD(class_args);
	COMPARE_NODE_FIELD(storedtype);

	return true;
}

static bool fc__equalCreateOpFamilyStmt(const CreateOpFamilyStmt *fc_a, const CreateOpFamilyStmt *fc_b)
{
	COMPARE_NODE_FIELD(opfamilyname);
	COMPARE_STRING_FIELD(amname);

	return true;
}

static bool fc__equalAlterOpFamilyStmt(const AlterOpFamilyStmt *fc_a, const AlterOpFamilyStmt *fc_b)
{
	COMPARE_NODE_FIELD(opfamilyname);
	COMPARE_STRING_FIELD(amname);
	COMPARE_SCALAR_FIELD(isDrop);
	COMPARE_NODE_FIELD(items);

	return true;
}

static bool fc__equalCreatedbStmt(const CreatedbStmt *fc_a, const CreatedbStmt *fc_b)
{
	COMPARE_STRING_FIELD(dbname);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalAlterDatabaseStmt(const AlterDatabaseStmt *fc_a, const AlterDatabaseStmt *fc_b)
{
	COMPARE_STRING_FIELD(dbname);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalAlterDatabaseRefreshCollStmt(const AlterDatabaseRefreshCollStmt *fc_a, const AlterDatabaseRefreshCollStmt *fc_b)
{
	COMPARE_STRING_FIELD(dbname);

	return true;
}

static bool fc__equalAlterDatabaseSetStmt(const AlterDatabaseSetStmt *fc_a, const AlterDatabaseSetStmt *fc_b)
{
	COMPARE_STRING_FIELD(dbname);
	COMPARE_NODE_FIELD(setstmt);

	return true;
}

static bool fc__equalDropdbStmt(const DropdbStmt *fc_a, const DropdbStmt *fc_b)
{
	COMPARE_STRING_FIELD(dbname);
	COMPARE_SCALAR_FIELD(missing_ok);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalVacuumStmt(const VacuumStmt *fc_a, const VacuumStmt *fc_b)
{
	COMPARE_NODE_FIELD(options);
	COMPARE_NODE_FIELD(rels);
	COMPARE_SCALAR_FIELD(is_vacuumcmd);

	return true;
}

static bool fc__equalVacuumRelation(const VacuumRelation *fc_a, const VacuumRelation *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_SCALAR_FIELD(oid);
	COMPARE_NODE_FIELD(va_cols);

	return true;
}

static bool fc__equalExplainStmt(const ExplainStmt *fc_a, const ExplainStmt *fc_b)
{
	COMPARE_NODE_FIELD(query);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalCreateTableAsStmt(const CreateTableAsStmt *fc_a, const CreateTableAsStmt *fc_b)
{
	COMPARE_NODE_FIELD(query);
	COMPARE_NODE_FIELD(into);
	COMPARE_SCALAR_FIELD(objtype);
	COMPARE_SCALAR_FIELD(is_select_into);
	COMPARE_SCALAR_FIELD(if_not_exists);

	return true;
}

static bool fc__equalRefreshMatViewStmt(const RefreshMatViewStmt *fc_a, const RefreshMatViewStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(concurrent);
	COMPARE_SCALAR_FIELD(skipData);
	COMPARE_NODE_FIELD(relation);

	return true;
}

static bool fc__equalReplicaIdentityStmt(const ReplicaIdentityStmt *fc_a, const ReplicaIdentityStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(identity_type);
	COMPARE_STRING_FIELD(name);

	return true;
}

static bool fc__equalAlterSystemStmt(const AlterSystemStmt *fc_a, const AlterSystemStmt *fc_b)
{
	COMPARE_NODE_FIELD(setstmt);

	return true;
}


static bool fc__equalCreateSeqStmt(const CreateSeqStmt *fc_a, const CreateSeqStmt *fc_b)
{
	COMPARE_NODE_FIELD(sequence);
	COMPARE_NODE_FIELD(options);
	COMPARE_SCALAR_FIELD(ownerId);
	COMPARE_SCALAR_FIELD(for_identity);
	COMPARE_SCALAR_FIELD(if_not_exists);

	return true;
}

static bool fc__equalAlterSeqStmt(const AlterSeqStmt *fc_a, const AlterSeqStmt *fc_b)
{
	COMPARE_NODE_FIELD(sequence);
	COMPARE_NODE_FIELD(options);
	COMPARE_SCALAR_FIELD(for_identity);
	COMPARE_SCALAR_FIELD(missing_ok);

	return true;
}

static bool fc__equalVariableSetStmt(const VariableSetStmt *fc_a, const VariableSetStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(kind);
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(args);
	COMPARE_SCALAR_FIELD(is_local);

	return true;
}

static bool fc__equalVariableShowStmt(const VariableShowStmt *fc_a, const VariableShowStmt *fc_b)
{
	COMPARE_STRING_FIELD(name);

	return true;
}

static bool fc__equalDiscardStmt(const DiscardStmt *fc_a, const DiscardStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(target);

	return true;
}

static bool fc__equalCreateTableSpaceStmt(const CreateTableSpaceStmt *fc_a, const CreateTableSpaceStmt *fc_b)
{
	COMPARE_STRING_FIELD(tablespacename);
	COMPARE_NODE_FIELD(owner);
	COMPARE_STRING_FIELD(location);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalDropTableSpaceStmt(const DropTableSpaceStmt *fc_a, const DropTableSpaceStmt *fc_b)
{
	COMPARE_STRING_FIELD(tablespacename);
	COMPARE_SCALAR_FIELD(missing_ok);

	return true;
}

static bool fc__equalAlterTableSpaceOptionsStmt(const AlterTableSpaceOptionsStmt *fc_a,
								 const AlterTableSpaceOptionsStmt *fc_b)
{
	COMPARE_STRING_FIELD(tablespacename);
	COMPARE_NODE_FIELD(options);
	COMPARE_SCALAR_FIELD(isReset);

	return true;
}

static bool fc__equalAlterTableMoveAllStmt(const AlterTableMoveAllStmt *fc_a,
							const AlterTableMoveAllStmt *fc_b)
{
	COMPARE_STRING_FIELD(orig_tablespacename);
	COMPARE_SCALAR_FIELD(objtype);
	COMPARE_NODE_FIELD(roles);
	COMPARE_STRING_FIELD(new_tablespacename);
	COMPARE_SCALAR_FIELD(nowait);

	return true;
}

static bool fc__equalCreateExtensionStmt(const CreateExtensionStmt *fc_a, const CreateExtensionStmt *fc_b)
{
	COMPARE_STRING_FIELD(extname);
	COMPARE_SCALAR_FIELD(if_not_exists);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalAlterExtensionStmt(const AlterExtensionStmt *fc_a, const AlterExtensionStmt *fc_b)
{
	COMPARE_STRING_FIELD(extname);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalAlterExtensionContentsStmt(const AlterExtensionContentsStmt *fc_a, const AlterExtensionContentsStmt *fc_b)
{
	COMPARE_STRING_FIELD(extname);
	COMPARE_SCALAR_FIELD(action);
	COMPARE_SCALAR_FIELD(objtype);
	COMPARE_NODE_FIELD(object);

	return true;
}

static bool fc__equalCreateFdwStmt(const CreateFdwStmt *fc_a, const CreateFdwStmt *fc_b)
{
	COMPARE_STRING_FIELD(fdwname);
	COMPARE_NODE_FIELD(func_options);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalAlterFdwStmt(const AlterFdwStmt *fc_a, const AlterFdwStmt *fc_b)
{
	COMPARE_STRING_FIELD(fdwname);
	COMPARE_NODE_FIELD(func_options);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalCreateForeignServerStmt(const CreateForeignServerStmt *fc_a, const CreateForeignServerStmt *fc_b)
{
	COMPARE_STRING_FIELD(servername);
	COMPARE_STRING_FIELD(servertype);
	COMPARE_STRING_FIELD(version);
	COMPARE_STRING_FIELD(fdwname);
	COMPARE_SCALAR_FIELD(if_not_exists);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalAlterForeignServerStmt(const AlterForeignServerStmt *fc_a, const AlterForeignServerStmt *fc_b)
{
	COMPARE_STRING_FIELD(servername);
	COMPARE_STRING_FIELD(version);
	COMPARE_NODE_FIELD(options);
	COMPARE_SCALAR_FIELD(has_version);

	return true;
}

static bool fc__equalCreateUserMappingStmt(const CreateUserMappingStmt *fc_a, const CreateUserMappingStmt *fc_b)
{
	COMPARE_NODE_FIELD(user);
	COMPARE_STRING_FIELD(servername);
	COMPARE_SCALAR_FIELD(if_not_exists);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalAlterUserMappingStmt(const AlterUserMappingStmt *fc_a, const AlterUserMappingStmt *fc_b)
{
	COMPARE_NODE_FIELD(user);
	COMPARE_STRING_FIELD(servername);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalDropUserMappingStmt(const DropUserMappingStmt *fc_a, const DropUserMappingStmt *fc_b)
{
	COMPARE_NODE_FIELD(user);
	COMPARE_STRING_FIELD(servername);
	COMPARE_SCALAR_FIELD(missing_ok);

	return true;
}

static bool fc__equalCreateForeignTableStmt(const CreateForeignTableStmt *fc_a, const CreateForeignTableStmt *fc_b)
{
	if (!fc__equalCreateStmt(&fc_a->base, &fc_b->base))
		return false;

	COMPARE_STRING_FIELD(servername);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalImportForeignSchemaStmt(const ImportForeignSchemaStmt *fc_a, const ImportForeignSchemaStmt *fc_b)
{
	COMPARE_STRING_FIELD(server_name);
	COMPARE_STRING_FIELD(remote_schema);
	COMPARE_STRING_FIELD(local_schema);
	COMPARE_SCALAR_FIELD(list_type);
	COMPARE_NODE_FIELD(table_list);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalCreateTransformStmt(const CreateTransformStmt *fc_a, const CreateTransformStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(replace);
	COMPARE_NODE_FIELD(type_name);
	COMPARE_STRING_FIELD(lang);
	COMPARE_NODE_FIELD(fromsql);
	COMPARE_NODE_FIELD(tosql);

	return true;
}

static bool fc__equalCreateAmStmt(const CreateAmStmt *fc_a, const CreateAmStmt *fc_b)
{
	COMPARE_STRING_FIELD(amname);
	COMPARE_NODE_FIELD(handler_name);
	COMPARE_SCALAR_FIELD(amtype);

	return true;
}

static bool fc__equalCreateTrigStmt(const CreateTrigStmt *fc_a, const CreateTrigStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(replace);
	COMPARE_SCALAR_FIELD(isconstraint);
	COMPARE_STRING_FIELD(trigname);
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(funcname);
	COMPARE_NODE_FIELD(args);
	COMPARE_SCALAR_FIELD(row);
	COMPARE_SCALAR_FIELD(timing);
	COMPARE_SCALAR_FIELD(events);
	COMPARE_NODE_FIELD(columns);
	COMPARE_NODE_FIELD(whenClause);
	COMPARE_NODE_FIELD(transitionRels);
	COMPARE_SCALAR_FIELD(deferrable);
	COMPARE_SCALAR_FIELD(initdeferred);
	COMPARE_NODE_FIELD(constrrel);

	return true;
}

static bool fc__equalCreateEventTrigStmt(const CreateEventTrigStmt *fc_a, const CreateEventTrigStmt *fc_b)
{
	COMPARE_STRING_FIELD(trigname);
	COMPARE_STRING_FIELD(eventname);
	COMPARE_NODE_FIELD(whenclause);
	COMPARE_NODE_FIELD(funcname);

	return true;
}

static bool fc__equalAlterEventTrigStmt(const AlterEventTrigStmt *fc_a, const AlterEventTrigStmt *fc_b)
{
	COMPARE_STRING_FIELD(trigname);
	COMPARE_SCALAR_FIELD(tgenabled);

	return true;
}

static bool fc__equalCreatePLangStmt(const CreatePLangStmt *fc_a, const CreatePLangStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(replace);
	COMPARE_STRING_FIELD(plname);
	COMPARE_NODE_FIELD(plhandler);
	COMPARE_NODE_FIELD(plinline);
	COMPARE_NODE_FIELD(plvalidator);
	COMPARE_SCALAR_FIELD(pltrusted);

	return true;
}

static bool fc__equalCreateRoleStmt(const CreateRoleStmt *fc_a, const CreateRoleStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(stmt_type);
	COMPARE_STRING_FIELD(role);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalAlterRoleStmt(const AlterRoleStmt *fc_a, const AlterRoleStmt *fc_b)
{
	COMPARE_NODE_FIELD(role);
	COMPARE_NODE_FIELD(options);
	COMPARE_SCALAR_FIELD(action);

	return true;
}

static bool fc__equalAlterRoleSetStmt(const AlterRoleSetStmt *fc_a, const AlterRoleSetStmt *fc_b)
{
	COMPARE_NODE_FIELD(role);
	COMPARE_STRING_FIELD(database);
	COMPARE_NODE_FIELD(setstmt);

	return true;
}

static bool fc__equalDropRoleStmt(const DropRoleStmt *fc_a, const DropRoleStmt *fc_b)
{
	COMPARE_NODE_FIELD(roles);
	COMPARE_SCALAR_FIELD(missing_ok);

	return true;
}

static bool fc__equalLockStmt(const LockStmt *fc_a, const LockStmt *fc_b)
{
	COMPARE_NODE_FIELD(relations);
	COMPARE_SCALAR_FIELD(mode);
	COMPARE_SCALAR_FIELD(nowait);

	return true;
}

static bool fc__equalConstraintsSetStmt(const ConstraintsSetStmt *fc_a, const ConstraintsSetStmt *fc_b)
{
	COMPARE_NODE_FIELD(constraints);
	COMPARE_SCALAR_FIELD(deferred);

	return true;
}

static bool fc__equalReindexStmt(const ReindexStmt *fc_a, const ReindexStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(kind);
	COMPARE_NODE_FIELD(relation);
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(params);

	return true;
}

static bool fc__equalCreateSchemaStmt(const CreateSchemaStmt *fc_a, const CreateSchemaStmt *fc_b)
{
	COMPARE_STRING_FIELD(schemaname);
	COMPARE_NODE_FIELD(authrole);
	COMPARE_NODE_FIELD(schemaElts);
	COMPARE_SCALAR_FIELD(if_not_exists);

	return true;
}

static bool fc__equalCreateConversionStmt(const CreateConversionStmt *fc_a, const CreateConversionStmt *fc_b)
{
	COMPARE_NODE_FIELD(conversion_name);
	COMPARE_STRING_FIELD(for_encoding_name);
	COMPARE_STRING_FIELD(to_encoding_name);
	COMPARE_NODE_FIELD(func_name);
	COMPARE_SCALAR_FIELD(def);

	return true;
}

static bool fc__equalCreateCastStmt(const CreateCastStmt *fc_a, const CreateCastStmt *fc_b)
{
	COMPARE_NODE_FIELD(sourcetype);
	COMPARE_NODE_FIELD(targettype);
	COMPARE_NODE_FIELD(func);
	COMPARE_SCALAR_FIELD(context);
	COMPARE_SCALAR_FIELD(inout);

	return true;
}

static bool fc__equalPrepareStmt(const PrepareStmt *fc_a, const PrepareStmt *fc_b)
{
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(argtypes);
	COMPARE_NODE_FIELD(query);

	return true;
}

static bool fc__equalExecuteStmt(const ExecuteStmt *fc_a, const ExecuteStmt *fc_b)
{
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(params);

	return true;
}

static bool fc__equalDeallocateStmt(const DeallocateStmt *fc_a, const DeallocateStmt *fc_b)
{
	COMPARE_STRING_FIELD(name);

	return true;
}

static bool fc__equalDropOwnedStmt(const DropOwnedStmt *fc_a, const DropOwnedStmt *fc_b)
{
	COMPARE_NODE_FIELD(roles);
	COMPARE_SCALAR_FIELD(behavior);

	return true;
}

static bool fc__equalReassignOwnedStmt(const ReassignOwnedStmt *fc_a, const ReassignOwnedStmt *fc_b)
{
	COMPARE_NODE_FIELD(roles);
	COMPARE_NODE_FIELD(newrole);

	return true;
}

static bool fc__equalAlterTSDictionaryStmt(const AlterTSDictionaryStmt *fc_a, const AlterTSDictionaryStmt *fc_b)
{
	COMPARE_NODE_FIELD(dictname);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalAlterTSConfigurationStmt(const AlterTSConfigurationStmt *fc_a,
							   const AlterTSConfigurationStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(kind);
	COMPARE_NODE_FIELD(cfgname);
	COMPARE_NODE_FIELD(tokentype);
	COMPARE_NODE_FIELD(dicts);
	COMPARE_SCALAR_FIELD(override);
	COMPARE_SCALAR_FIELD(replace);
	COMPARE_SCALAR_FIELD(missing_ok);

	return true;
}

static bool fc__equalPublicationObject(const PublicationObjSpec *fc_a,
						const PublicationObjSpec *fc_b)
{
	COMPARE_SCALAR_FIELD(pubobjtype);
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(pubtable);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalPublicationTable(const PublicationTable *fc_a, const PublicationTable *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(whereClause);
	COMPARE_NODE_FIELD(columns);

	return true;
}

static bool fc__equalCreatePublicationStmt(const CreatePublicationStmt *fc_a,
							const CreatePublicationStmt *fc_b)
{
	COMPARE_STRING_FIELD(pubname);
	COMPARE_NODE_FIELD(options);
	COMPARE_NODE_FIELD(pubobjects);
	COMPARE_SCALAR_FIELD(for_all_tables);

	return true;
}

static bool fc__equalAlterPublicationStmt(const AlterPublicationStmt *fc_a,
						   const AlterPublicationStmt *fc_b)
{
	COMPARE_STRING_FIELD(pubname);
	COMPARE_NODE_FIELD(options);
	COMPARE_NODE_FIELD(pubobjects);
	COMPARE_SCALAR_FIELD(for_all_tables);
	COMPARE_SCALAR_FIELD(action);

	return true;
}

static bool fc__equalCreateSubscriptionStmt(const CreateSubscriptionStmt *fc_a,
							 const CreateSubscriptionStmt *fc_b)
{
	COMPARE_STRING_FIELD(subname);
	COMPARE_STRING_FIELD(conninfo);
	COMPARE_NODE_FIELD(publication);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalAlterSubscriptionStmt(const AlterSubscriptionStmt *fc_a,
							const AlterSubscriptionStmt *fc_b)
{
	COMPARE_SCALAR_FIELD(kind);
	COMPARE_STRING_FIELD(subname);
	COMPARE_STRING_FIELD(conninfo);
	COMPARE_NODE_FIELD(publication);
	COMPARE_NODE_FIELD(options);

	return true;
}

static bool fc__equalDropSubscriptionStmt(const DropSubscriptionStmt *fc_a,
						   const DropSubscriptionStmt *fc_b)
{
	COMPARE_STRING_FIELD(subname);
	COMPARE_SCALAR_FIELD(missing_ok);
	COMPARE_SCALAR_FIELD(behavior);

	return true;
}

static bool fc__equalCreatePolicyStmt(const CreatePolicyStmt *fc_a, const CreatePolicyStmt *fc_b)
{
	COMPARE_STRING_FIELD(policy_name);
	COMPARE_NODE_FIELD(table);
	COMPARE_STRING_FIELD(cmd_name);
	COMPARE_SCALAR_FIELD(permissive);
	COMPARE_NODE_FIELD(roles);
	COMPARE_NODE_FIELD(qual);
	COMPARE_NODE_FIELD(with_check);

	return true;
}

static bool fc__equalAlterPolicyStmt(const AlterPolicyStmt *fc_a, const AlterPolicyStmt *fc_b)
{
	COMPARE_STRING_FIELD(policy_name);
	COMPARE_NODE_FIELD(table);
	COMPARE_NODE_FIELD(roles);
	COMPARE_NODE_FIELD(qual);
	COMPARE_NODE_FIELD(with_check);

	return true;
}

static bool fc__equalA_Expr(const A_Expr *fc_a, const A_Expr *fc_b)
{
	COMPARE_SCALAR_FIELD(kind);
	COMPARE_NODE_FIELD(name);
	COMPARE_NODE_FIELD(lexpr);
	COMPARE_NODE_FIELD(rexpr);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalColumnRef(const ColumnRef *fc_a, const ColumnRef *fc_b)
{
	COMPARE_NODE_FIELD(fields);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalParamRef(const ParamRef *fc_a, const ParamRef *fc_b)
{
	COMPARE_SCALAR_FIELD(number);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalA_Const(const A_Const *fc_a, const A_Const *fc_b)
{
	/*
	 * 对 in-line val 字段的解决方法。当 isnull 为真时，val 无效。
	 */
	if (!fc_a->isnull && !fc_b->isnull &&
		!equal(&fc_a->val, &fc_b->val))
		return false;
	COMPARE_SCALAR_FIELD(isnull);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalFuncCall(const FuncCall *fc_a, const FuncCall *fc_b)
{
	COMPARE_NODE_FIELD(funcname);
	COMPARE_NODE_FIELD(args);
	COMPARE_NODE_FIELD(agg_order);
	COMPARE_NODE_FIELD(agg_filter);
	COMPARE_NODE_FIELD(over);
	COMPARE_SCALAR_FIELD(agg_within_group);
	COMPARE_SCALAR_FIELD(agg_star);
	COMPARE_SCALAR_FIELD(agg_distinct);
	COMPARE_SCALAR_FIELD(func_variadic);
	COMPARE_COERCIONFORM_FIELD(funcformat);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalA_Star(const A_Star *fc_a, const A_Star *fc_b)
{
	return true;
}

static bool fc__equalA_Indices(const A_Indices *fc_a, const A_Indices *fc_b)
{
	COMPARE_SCALAR_FIELD(is_slice);
	COMPARE_NODE_FIELD(lidx);
	COMPARE_NODE_FIELD(uidx);

	return true;
}

static bool fc__equalA_Indirection(const A_Indirection *fc_a, const A_Indirection *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_NODE_FIELD(indirection);

	return true;
}

static bool fc__equalA_ArrayExpr(const A_ArrayExpr *fc_a, const A_ArrayExpr *fc_b)
{
	COMPARE_NODE_FIELD(elements);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalResTarget(const ResTarget *fc_a, const ResTarget *fc_b)
{
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(indirection);
	COMPARE_NODE_FIELD(val);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalMultiAssignRef(const MultiAssignRef *fc_a, const MultiAssignRef *fc_b)
{
	COMPARE_NODE_FIELD(source);
	COMPARE_SCALAR_FIELD(colno);
	COMPARE_SCALAR_FIELD(ncolumns);

	return true;
}

static bool fc__equalTypeName(const TypeName *fc_a, const TypeName *fc_b)
{
	COMPARE_NODE_FIELD(names);
	COMPARE_SCALAR_FIELD(typeOid);
	COMPARE_SCALAR_FIELD(setof);
	COMPARE_SCALAR_FIELD(pct_type);
	COMPARE_NODE_FIELD(typmods);
	COMPARE_SCALAR_FIELD(typemod);
	COMPARE_NODE_FIELD(arrayBounds);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalTypeCast(const TypeCast *fc_a, const TypeCast *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_NODE_FIELD(typeName);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalCollateClause(const CollateClause *fc_a, const CollateClause *fc_b)
{
	COMPARE_NODE_FIELD(arg);
	COMPARE_NODE_FIELD(collname);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalSortBy(const SortBy *fc_a, const SortBy *fc_b)
{
	COMPARE_NODE_FIELD(node);
	COMPARE_SCALAR_FIELD(sortby_dir);
	COMPARE_SCALAR_FIELD(sortby_nulls);
	COMPARE_NODE_FIELD(useOp);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalWindowDef(const WindowDef *fc_a, const WindowDef *fc_b)
{
	COMPARE_STRING_FIELD(name);
	COMPARE_STRING_FIELD(refname);
	COMPARE_NODE_FIELD(partitionClause);
	COMPARE_NODE_FIELD(orderClause);
	COMPARE_SCALAR_FIELD(frameOptions);
	COMPARE_NODE_FIELD(startOffset);
	COMPARE_NODE_FIELD(endOffset);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalRangeSubselect(const RangeSubselect *fc_a, const RangeSubselect *fc_b)
{
	COMPARE_SCALAR_FIELD(lateral);
	COMPARE_NODE_FIELD(subquery);
	COMPARE_NODE_FIELD(alias);

	return true;
}

static bool fc__equalRangeFunction(const RangeFunction *fc_a, const RangeFunction *fc_b)
{
	COMPARE_SCALAR_FIELD(lateral);
	COMPARE_SCALAR_FIELD(ordinality);
	COMPARE_SCALAR_FIELD(is_rowsfrom);
	COMPARE_NODE_FIELD(functions);
	COMPARE_NODE_FIELD(alias);
	COMPARE_NODE_FIELD(coldeflist);

	return true;
}

static bool fc__equalRangeTableSample(const RangeTableSample *fc_a, const RangeTableSample *fc_b)
{
	COMPARE_NODE_FIELD(relation);
	COMPARE_NODE_FIELD(method);
	COMPARE_NODE_FIELD(args);
	COMPARE_NODE_FIELD(repeatable);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalRangeTableFunc(const RangeTableFunc *fc_a, const RangeTableFunc *fc_b)
{
	COMPARE_SCALAR_FIELD(lateral);
	COMPARE_NODE_FIELD(docexpr);
	COMPARE_NODE_FIELD(rowexpr);
	COMPARE_NODE_FIELD(namespaces);
	COMPARE_NODE_FIELD(columns);
	COMPARE_NODE_FIELD(alias);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalRangeTableFuncCol(const RangeTableFuncCol *fc_a, const RangeTableFuncCol *fc_b)
{
	COMPARE_STRING_FIELD(colname);
	COMPARE_NODE_FIELD(typeName);
	COMPARE_SCALAR_FIELD(for_ordinality);
	COMPARE_SCALAR_FIELD(is_not_null);
	COMPARE_NODE_FIELD(colexpr);
	COMPARE_NODE_FIELD(coldefexpr);
	COMPARE_LOCATION_FIELD(location);

	return true;
}


static bool fc__equalIndexElem(const IndexElem *fc_a, const IndexElem *fc_b)
{
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(expr);
	COMPARE_STRING_FIELD(indexcolname);
	COMPARE_NODE_FIELD(collation);
	COMPARE_NODE_FIELD(opclass);
	COMPARE_NODE_FIELD(opclassopts);
	COMPARE_SCALAR_FIELD(ordering);
	COMPARE_SCALAR_FIELD(nulls_ordering);

	return true;
}


static bool fc__equalStatsElem(const StatsElem *fc_a, const StatsElem *fc_b)
{
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(expr);

	return true;
}

static bool fc__equalColumnDef(const ColumnDef *fc_a, const ColumnDef *fc_b)
{
	COMPARE_STRING_FIELD(colname);
	COMPARE_NODE_FIELD(typeName);
	COMPARE_STRING_FIELD(compression);
	COMPARE_SCALAR_FIELD(inhcount);
	COMPARE_SCALAR_FIELD(is_local);
	COMPARE_SCALAR_FIELD(is_not_null);
	COMPARE_SCALAR_FIELD(is_from_type);
	COMPARE_SCALAR_FIELD(storage);
	COMPARE_NODE_FIELD(raw_default);
	COMPARE_NODE_FIELD(cooked_default);
	COMPARE_SCALAR_FIELD(identity);
	COMPARE_NODE_FIELD(identitySequence);
	COMPARE_SCALAR_FIELD(generated);
	COMPARE_NODE_FIELD(collClause);
	COMPARE_SCALAR_FIELD(collOid);
	COMPARE_NODE_FIELD(constraints);
	COMPARE_NODE_FIELD(fdwoptions);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalConstraint(const Constraint *fc_a, const Constraint *fc_b)
{
	COMPARE_SCALAR_FIELD(contype);
	COMPARE_STRING_FIELD(conname);
	COMPARE_SCALAR_FIELD(deferrable);
	COMPARE_SCALAR_FIELD(initdeferred);
	COMPARE_LOCATION_FIELD(location);
	COMPARE_SCALAR_FIELD(is_no_inherit);
	COMPARE_NODE_FIELD(raw_expr);
	COMPARE_STRING_FIELD(cooked_expr);
	COMPARE_SCALAR_FIELD(generated_when);
	COMPARE_SCALAR_FIELD(nulls_not_distinct);
	COMPARE_NODE_FIELD(keys);
	COMPARE_NODE_FIELD(including);
	COMPARE_NODE_FIELD(exclusions);
	COMPARE_NODE_FIELD(options);
	COMPARE_STRING_FIELD(indexname);
	COMPARE_STRING_FIELD(indexspace);
	COMPARE_SCALAR_FIELD(reset_default_tblspc);
	COMPARE_STRING_FIELD(access_method);
	COMPARE_NODE_FIELD(where_clause);
	COMPARE_NODE_FIELD(pktable);
	COMPARE_NODE_FIELD(fk_attrs);
	COMPARE_NODE_FIELD(pk_attrs);
	COMPARE_SCALAR_FIELD(fk_matchtype);
	COMPARE_SCALAR_FIELD(fk_upd_action);
	COMPARE_SCALAR_FIELD(fk_del_action);
	COMPARE_NODE_FIELD(fk_del_set_cols);
	COMPARE_NODE_FIELD(old_conpfeqop);
	COMPARE_SCALAR_FIELD(old_pktable_oid);
	COMPARE_SCALAR_FIELD(skip_validation);
	COMPARE_SCALAR_FIELD(initially_valid);

	return true;
}

static bool fc__equalDefElem(const DefElem *fc_a, const DefElem *fc_b)
{
	COMPARE_STRING_FIELD(defnamespace);
	COMPARE_STRING_FIELD(defname);
	COMPARE_NODE_FIELD(arg);
	COMPARE_SCALAR_FIELD(defaction);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalLockingClause(const LockingClause *fc_a, const LockingClause *fc_b)
{
	COMPARE_NODE_FIELD(lockedRels);
	COMPARE_SCALAR_FIELD(strength);
	COMPARE_SCALAR_FIELD(waitPolicy);

	return true;
}

static bool fc__equalRangeTblEntry(const RangeTblEntry *fc_a, const RangeTblEntry *fc_b)
{
	COMPARE_SCALAR_FIELD(rtekind);
	COMPARE_SCALAR_FIELD(relid);
	COMPARE_SCALAR_FIELD(relkind);
	COMPARE_SCALAR_FIELD(rellockmode);
	COMPARE_NODE_FIELD(tablesample);
	COMPARE_NODE_FIELD(subquery);
	COMPARE_SCALAR_FIELD(security_barrier);
	COMPARE_SCALAR_FIELD(jointype);
	COMPARE_SCALAR_FIELD(joinmergedcols);
	COMPARE_NODE_FIELD(joinaliasvars);
	COMPARE_NODE_FIELD(joinleftcols);
	COMPARE_NODE_FIELD(joinrightcols);
	COMPARE_NODE_FIELD(join_using_alias);
	COMPARE_NODE_FIELD(functions);
	COMPARE_SCALAR_FIELD(funcordinality);
	COMPARE_NODE_FIELD(tablefunc);
	COMPARE_NODE_FIELD(values_lists);
	COMPARE_STRING_FIELD(ctename);
	COMPARE_SCALAR_FIELD(ctelevelsup);
	COMPARE_SCALAR_FIELD(self_reference);
	COMPARE_NODE_FIELD(coltypes);
	COMPARE_NODE_FIELD(coltypmods);
	COMPARE_NODE_FIELD(colcollations);
	COMPARE_STRING_FIELD(enrname);
	COMPARE_SCALAR_FIELD(enrtuples);
	COMPARE_NODE_FIELD(alias);
	COMPARE_NODE_FIELD(eref);
	COMPARE_SCALAR_FIELD(lateral);
	COMPARE_SCALAR_FIELD(inh);
	COMPARE_SCALAR_FIELD(inFromCl);
	COMPARE_SCALAR_FIELD(requiredPerms);
	COMPARE_SCALAR_FIELD(checkAsUser);
	COMPARE_BITMAPSET_FIELD(selectedCols);
	COMPARE_BITMAPSET_FIELD(insertedCols);
	COMPARE_BITMAPSET_FIELD(updatedCols);
	COMPARE_BITMAPSET_FIELD(extraUpdatedCols);
	COMPARE_NODE_FIELD(securityQuals);

	return true;
}

static bool fc__equalRangeTblFunction(const RangeTblFunction *fc_a, const RangeTblFunction *fc_b)
{
	COMPARE_NODE_FIELD(funcexpr);
	COMPARE_SCALAR_FIELD(funccolcount);
	COMPARE_NODE_FIELD(funccolnames);
	COMPARE_NODE_FIELD(funccoltypes);
	COMPARE_NODE_FIELD(funccoltypmods);
	COMPARE_NODE_FIELD(funccolcollations);
	COMPARE_BITMAPSET_FIELD(funcparams);

	return true;
}

static bool fc__equalTableSampleClause(const TableSampleClause *fc_a, const TableSampleClause *fc_b)
{
	COMPARE_SCALAR_FIELD(tsmhandler);
	COMPARE_NODE_FIELD(args);
	COMPARE_NODE_FIELD(repeatable);

	return true;
}

static bool fc__equalWithCheckOption(const WithCheckOption *fc_a, const WithCheckOption *fc_b)
{
	COMPARE_SCALAR_FIELD(kind);
	COMPARE_STRING_FIELD(relname);
	COMPARE_STRING_FIELD(polname);
	COMPARE_NODE_FIELD(qual);
	COMPARE_SCALAR_FIELD(cascaded);

	return true;
}

static bool fc__equalSortGroupClause(const SortGroupClause *fc_a, const SortGroupClause *fc_b)
{
	COMPARE_SCALAR_FIELD(tleSortGroupRef);
	COMPARE_SCALAR_FIELD(eqop);
	COMPARE_SCALAR_FIELD(sortop);
	COMPARE_SCALAR_FIELD(nulls_first);
	COMPARE_SCALAR_FIELD(hashable);

	return true;
}

static bool fc__equalGroupingSet(const GroupingSet *fc_a, const GroupingSet *fc_b)
{
	COMPARE_SCALAR_FIELD(kind);
	COMPARE_NODE_FIELD(content);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalWindowClause(const WindowClause *fc_a, const WindowClause *fc_b)
{
	COMPARE_STRING_FIELD(name);
	COMPARE_STRING_FIELD(refname);
	COMPARE_NODE_FIELD(partitionClause);
	COMPARE_NODE_FIELD(orderClause);
	COMPARE_SCALAR_FIELD(frameOptions);
	COMPARE_NODE_FIELD(startOffset);
	COMPARE_NODE_FIELD(endOffset);
	COMPARE_NODE_FIELD(runCondition);
	COMPARE_SCALAR_FIELD(startInRangeFunc);
	COMPARE_SCALAR_FIELD(endInRangeFunc);
	COMPARE_SCALAR_FIELD(inRangeColl);
	COMPARE_SCALAR_FIELD(inRangeAsc);
	COMPARE_SCALAR_FIELD(inRangeNullsFirst);
	COMPARE_SCALAR_FIELD(winref);
	COMPARE_SCALAR_FIELD(copiedOrder);

	return true;
}

static bool fc__equalRowMarkClause(const RowMarkClause *fc_a, const RowMarkClause *fc_b)
{
	COMPARE_SCALAR_FIELD(rti);
	COMPARE_SCALAR_FIELD(strength);
	COMPARE_SCALAR_FIELD(waitPolicy);
	COMPARE_SCALAR_FIELD(pushedDown);

	return true;
}

static bool fc__equalWithClause(const WithClause *fc_a, const WithClause *fc_b)
{
	COMPARE_NODE_FIELD(ctes);
	COMPARE_SCALAR_FIELD(recursive);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalInferClause(const InferClause *fc_a, const InferClause *fc_b)
{
	COMPARE_NODE_FIELD(indexElems);
	COMPARE_NODE_FIELD(whereClause);
	COMPARE_STRING_FIELD(conname);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalOnConflictClause(const OnConflictClause *fc_a, const OnConflictClause *fc_b)
{
	COMPARE_SCALAR_FIELD(action);
	COMPARE_NODE_FIELD(infer);
	COMPARE_NODE_FIELD(targetList);
	COMPARE_NODE_FIELD(whereClause);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalCTESearchClause(const CTESearchClause *fc_a, const CTESearchClause *fc_b)
{
	COMPARE_NODE_FIELD(search_col_list);
	COMPARE_SCALAR_FIELD(search_breadth_first);
	COMPARE_STRING_FIELD(search_seq_column);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalCTECycleClause(const CTECycleClause *fc_a, const CTECycleClause *fc_b)
{
	COMPARE_NODE_FIELD(cycle_col_list);
	COMPARE_STRING_FIELD(cycle_mark_column);
	COMPARE_NODE_FIELD(cycle_mark_value);
	COMPARE_NODE_FIELD(cycle_mark_default);
	COMPARE_STRING_FIELD(cycle_path_column);
	COMPARE_LOCATION_FIELD(location);
	COMPARE_SCALAR_FIELD(cycle_mark_type);
	COMPARE_SCALAR_FIELD(cycle_mark_typmod);
	COMPARE_SCALAR_FIELD(cycle_mark_collation);
	COMPARE_SCALAR_FIELD(cycle_mark_neop);

	return true;
}

static bool fc__equalCommonTableExpr(const CommonTableExpr *fc_a, const CommonTableExpr *fc_b)
{
	COMPARE_STRING_FIELD(ctename);
	COMPARE_NODE_FIELD(aliascolnames);
	COMPARE_SCALAR_FIELD(ctematerialized);
	COMPARE_NODE_FIELD(ctequery);
	COMPARE_NODE_FIELD(search_clause);
	COMPARE_NODE_FIELD(cycle_clause);
	COMPARE_LOCATION_FIELD(location);
	COMPARE_SCALAR_FIELD(cterecursive);
	COMPARE_SCALAR_FIELD(cterefcount);
	COMPARE_NODE_FIELD(ctecolnames);
	COMPARE_NODE_FIELD(ctecoltypes);
	COMPARE_NODE_FIELD(ctecoltypmods);
	COMPARE_NODE_FIELD(ctecolcollations);

	return true;
}

static bool fc__equalMergeWhenClause(const MergeWhenClause *fc_a, const MergeWhenClause *fc_b)
{
	COMPARE_SCALAR_FIELD(matched);
	COMPARE_SCALAR_FIELD(commandType);
	COMPARE_SCALAR_FIELD(override);
	COMPARE_NODE_FIELD(condition);
	COMPARE_NODE_FIELD(targetList);
	COMPARE_NODE_FIELD(values);

	return true;
}

static bool fc__equalMergeAction(const MergeAction *fc_a, const MergeAction *fc_b)
{
	COMPARE_SCALAR_FIELD(matched);
	COMPARE_SCALAR_FIELD(commandType);
	COMPARE_SCALAR_FIELD(override);
	COMPARE_NODE_FIELD(qual);
	COMPARE_NODE_FIELD(targetList);
	COMPARE_NODE_FIELD(updateColnos);

	return true;
}

static bool fc__equalXmlSerialize(const XmlSerialize *fc_a, const XmlSerialize *fc_b)
{
	COMPARE_SCALAR_FIELD(xmloption);
	COMPARE_NODE_FIELD(expr);
	COMPARE_NODE_FIELD(typeName);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalRoleSpec(const RoleSpec *fc_a, const RoleSpec *fc_b)
{
	COMPARE_SCALAR_FIELD(roletype);
	COMPARE_STRING_FIELD(rolename);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalTriggerTransition(const TriggerTransition *fc_a, const TriggerTransition *fc_b)
{
	COMPARE_STRING_FIELD(name);
	COMPARE_SCALAR_FIELD(isNew);
	COMPARE_SCALAR_FIELD(isTable);

	return true;
}

static bool fc__equalPartitionElem(const PartitionElem *fc_a, const PartitionElem *fc_b)
{
	COMPARE_STRING_FIELD(name);
	COMPARE_NODE_FIELD(expr);
	COMPARE_NODE_FIELD(collation);
	COMPARE_NODE_FIELD(opclass);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalPartitionSpec(const PartitionSpec *fc_a, const PartitionSpec *fc_b)
{
	COMPARE_STRING_FIELD(strategy);
	COMPARE_NODE_FIELD(partParams);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalPartitionBoundSpec(const PartitionBoundSpec *fc_a, const PartitionBoundSpec *fc_b)
{
	COMPARE_SCALAR_FIELD(strategy);
	COMPARE_SCALAR_FIELD(is_default);
	COMPARE_SCALAR_FIELD(modulus);
	COMPARE_SCALAR_FIELD(remainder);
	COMPARE_NODE_FIELD(listdatums);
	COMPARE_NODE_FIELD(lowerdatums);
	COMPARE_NODE_FIELD(upperdatums);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalPartitionRangeDatum(const PartitionRangeDatum *fc_a, const PartitionRangeDatum *fc_b)
{
	COMPARE_SCALAR_FIELD(kind);
	COMPARE_NODE_FIELD(value);
	COMPARE_LOCATION_FIELD(location);

	return true;
}

static bool fc__equalPartitionCmd(const PartitionCmd *fc_a, const PartitionCmd *fc_b)
{
	COMPARE_NODE_FIELD(name);
	COMPARE_NODE_FIELD(bound);
	COMPARE_SCALAR_FIELD(concurrent);

	return true;
}

/*
 * 来自 pg_list.h 的内容
 */

static bool fc__equalList(const List *fc_a, const List *fc_b)
{
	const ListCell *fc_item_a;
	const ListCell *fc_item_b;

	/*
	 * 尝试在遍历所有列表元素之前通过简单的标量检查进行拒绝…
	 */
	COMPARE_SCALAR_FIELD(type);
	COMPARE_SCALAR_FIELD(length);

	/*
	 * 为了效率，我们将切换放在循环外；这可能不值得这样做…
	 */
	switch (fc_a->type)
	{
		case T_List:
			forboth(fc_item_a, fc_a, fc_item_b, fc_b)
			{
				if (!equal(lfirst(fc_item_a), lfirst(fc_item_b)))
					return false;
			}
			break;
		case T_IntList:
			forboth(fc_item_a, fc_a, fc_item_b, fc_b)
			{
				if (lfirst_int(fc_item_a) != lfirst_int(fc_item_b))
					return false;
			}
			break;
		case T_OidList:
			forboth(fc_item_a, fc_a, fc_item_b, fc_b)
			{
				if (lfirst_oid(fc_item_a) != lfirst_oid(fc_item_b))
					return false;
			}
			break;
		default:
			elog(ERROR, "unrecognized list node type: %d",
				 (int) fc_a->type);
			return false;		/* 保持编译器安静 */
	}

	/*
	 * 如果我们到了这里，我们应该已经耗尽了两个列表的元素
	 */
	Assert(fc_item_a == NULL);
	Assert(fc_item_b == NULL);

	return true;
}

/*
 * 来自 value.h 的内容
 */

static bool fc__equalInteger(const Integer *fc_a, const Integer *fc_b)
{
	COMPARE_SCALAR_FIELD(ival);

	return true;
}

static bool fc__equalFloat(const Float *fc_a, const Float *fc_b)
{
	COMPARE_STRING_FIELD(fval);

	return true;
}

static bool fc__equalBoolean(const Boolean *fc_a, const Boolean *fc_b)
{
	COMPARE_SCALAR_FIELD(boolval);

	return true;
}

static bool fc__equalString(const String *fc_a, const String *fc_b)
{
	COMPARE_STRING_FIELD(sval);

	return true;
}

static bool fc__equalBitString(const BitString *fc_a, const BitString *fc_b)
{
	COMPARE_STRING_FIELD(bsval);

	return true;
}

/*
 * 相等
 *	  返回两个节点是否相等
 */
bool equal(const void *fc_a, const void *fc_b)
{
	bool		fc_retval;

	if (fc_a == fc_b)
		return true;

	/*
	 * 注意 a != b，因此它们中只能有一个是 NULL
	 */
	if (fc_a == NULL || fc_b == NULL)
		return false;

	/*
	 * 它们是否是相同类型的节点？
	 */
	if (nodeTag(fc_a) != nodeTag(fc_b))
		return false;

	/* 防止因过于复杂的表达式导致栈溢出 */
	check_stack_depth();

	switch (nodeTag(fc_a))
	{
			/*
			 * 基本节点
			 */
		case T_Alias:
			fc_retval = fc__equalAlias(fc_a, fc_b);
			break;
		case T_RangeVar:
			fc_retval = fc__equalRangeVar(fc_a, fc_b);
			break;
		case T_TableFunc:
			fc_retval = fc__equalTableFunc(fc_a, fc_b);
			break;
		case T_IntoClause:
			fc_retval = fc__equalIntoClause(fc_a, fc_b);
			break;
		case T_Var:
			fc_retval = fc__equalVar(fc_a, fc_b);
			break;
		case T_Const:
			fc_retval = fc__equalConst(fc_a, fc_b);
			break;
		case T_Param:
			fc_retval = fc__equalParam(fc_a, fc_b);
			break;
		case T_Aggref:
			fc_retval = fc__equalAggref(fc_a, fc_b);
			break;
		case T_GroupingFunc:
			fc_retval = fc__equalGroupingFunc(fc_a, fc_b);
			break;
		case T_WindowFunc:
			fc_retval = fc__equalWindowFunc(fc_a, fc_b);
			break;
		case T_SubscriptingRef:
			fc_retval = fc__equalSubscriptingRef(fc_a, fc_b);
			break;
		case T_FuncExpr:
			fc_retval = fc__equalFuncExpr(fc_a, fc_b);
			break;
		case T_NamedArgExpr:
			fc_retval = fc__equalNamedArgExpr(fc_a, fc_b);
			break;
		case T_OpExpr:
			fc_retval = fc__equalOpExpr(fc_a, fc_b);
			break;
		case T_DistinctExpr:
			fc_retval = fc__equalDistinctExpr(fc_a, fc_b);
			break;
		case T_NullIfExpr:
			fc_retval = fc__equalNullIfExpr(fc_a, fc_b);
			break;
		case T_ScalarArrayOpExpr:
			fc_retval = fc__equalScalarArrayOpExpr(fc_a, fc_b);
			break;
		case T_BoolExpr:
			fc_retval = fc__equalBoolExpr(fc_a, fc_b);
			break;
		case T_SubLink:
			fc_retval = fc__equalSubLink(fc_a, fc_b);
			break;
		case T_SubPlan:
			fc_retval = fc__equalSubPlan(fc_a, fc_b);
			break;
		case T_AlternativeSubPlan:
			fc_retval = fc__equalAlternativeSubPlan(fc_a, fc_b);
			break;
		case T_FieldSelect:
			fc_retval = fc__equalFieldSelect(fc_a, fc_b);
			break;
		case T_FieldStore:
			fc_retval = fc__equalFieldStore(fc_a, fc_b);
			break;
		case T_RelabelType:
			fc_retval = fc__equalRelabelType(fc_a, fc_b);
			break;
		case T_CoerceViaIO:
			fc_retval = fc__equalCoerceViaIO(fc_a, fc_b);
			break;
		case T_ArrayCoerceExpr:
			fc_retval = fc__equalArrayCoerceExpr(fc_a, fc_b);
			break;
		case T_ConvertRowtypeExpr:
			fc_retval = fc__equalConvertRowtypeExpr(fc_a, fc_b);
			break;
		case T_CollateExpr:
			fc_retval = fc__equalCollateExpr(fc_a, fc_b);
			break;
		case T_CaseExpr:
			fc_retval = fc__equalCaseExpr(fc_a, fc_b);
			break;
		case T_CaseWhen:
			fc_retval = fc__equalCaseWhen(fc_a, fc_b);
			break;
		case T_CaseTestExpr:
			fc_retval = fc__equalCaseTestExpr(fc_a, fc_b);
			break;
		case T_ArrayExpr:
			fc_retval = fc__equalArrayExpr(fc_a, fc_b);
			break;
		case T_RowExpr:
			fc_retval = fc__equalRowExpr(fc_a, fc_b);
			break;
		case T_RowCompareExpr:
			fc_retval = fc__equalRowCompareExpr(fc_a, fc_b);
			break;
		case T_CoalesceExpr:
			fc_retval = fc__equalCoalesceExpr(fc_a, fc_b);
			break;
		case T_MinMaxExpr:
			fc_retval = fc__equalMinMaxExpr(fc_a, fc_b);
			break;
		case T_SQLValueFunction:
			fc_retval = fc__equalSQLValueFunction(fc_a, fc_b);
			break;
		case T_XmlExpr:
			fc_retval = fc__equalXmlExpr(fc_a, fc_b);
			break;
		case T_NullTest:
			fc_retval = fc__equalNullTest(fc_a, fc_b);
			break;
		case T_BooleanTest:
			fc_retval = fc__equalBooleanTest(fc_a, fc_b);
			break;
		case T_CoerceToDomain:
			fc_retval = fc__equalCoerceToDomain(fc_a, fc_b);
			break;
		case T_CoerceToDomainValue:
			fc_retval = fc__equalCoerceToDomainValue(fc_a, fc_b);
			break;
		case T_SetToDefault:
			fc_retval = fc__equalSetToDefault(fc_a, fc_b);
			break;
		case T_CurrentOfExpr:
			fc_retval = fc__equalCurrentOfExpr(fc_a, fc_b);
			break;
		case T_NextValueExpr:
			fc_retval = fc__equalNextValueExpr(fc_a, fc_b);
			break;
		case T_InferenceElem:
			fc_retval = fc__equalInferenceElem(fc_a, fc_b);
			break;
		case T_TargetEntry:
			fc_retval = fc__equalTargetEntry(fc_a, fc_b);
			break;
		case T_RangeTblRef:
			fc_retval = fc__equalRangeTblRef(fc_a, fc_b);
			break;
		case T_FromExpr:
			fc_retval = fc__equalFromExpr(fc_a, fc_b);
			break;
		case T_OnConflictExpr:
			fc_retval = fc__equalOnConflictExpr(fc_a, fc_b);
			break;
		case T_JoinExpr:
			fc_retval = fc__equalJoinExpr(fc_a, fc_b);
			break;

			/*
			 * 关系节点
			 */
		case T_PathKey:
			fc_retval = fc__equalPathKey(fc_a, fc_b);
			break;
		case T_RestrictInfo:
			fc_retval = fc__equalRestrictInfo(fc_a, fc_b);
			break;
		case T_PlaceHolderVar:
			fc_retval = fc__equalPlaceHolderVar(fc_a, fc_b);
			break;
		case T_SpecialJoinInfo:
			fc_retval = fc__equalSpecialJoinInfo(fc_a, fc_b);
			break;
		case T_AppendRelInfo:
			fc_retval = fc__equalAppendRelInfo(fc_a, fc_b);
			break;
		case T_PlaceHolderInfo:
			fc_retval = fc__equalPlaceHolderInfo(fc_a, fc_b);
			break;

		case T_List:
		case T_IntList:
		case T_OidList:
			fc_retval = fc__equalList(fc_a, fc_b);
			break;

		case T_Integer:
			fc_retval = fc__equalInteger(fc_a, fc_b);
			break;
		case T_Float:
			fc_retval = fc__equalFloat(fc_a, fc_b);
			break;
		case T_Boolean:
			fc_retval = fc__equalBoolean(fc_a, fc_b);
			break;
		case T_String:
			fc_retval = fc__equalString(fc_a, fc_b);
			break;
		case T_BitString:
			fc_retval = fc__equalBitString(fc_a, fc_b);
			break;

			/*
			 * 可扩展节点
			 */
		case T_ExtensibleNode:
			fc_retval = fc__equalExtensibleNode(fc_a, fc_b);
			break;

			/*
			 * 解析节点
			 */
		case T_Query:
			fc_retval = fc__equalQuery(fc_a, fc_b);
			break;
		case T_RawStmt:
			fc_retval = fc__equalRawStmt(fc_a, fc_b);
			break;
		case T_InsertStmt:
			fc_retval = fc__equalInsertStmt(fc_a, fc_b);
			break;
		case T_DeleteStmt:
			fc_retval = fc__equalDeleteStmt(fc_a, fc_b);
			break;
		case T_UpdateStmt:
			fc_retval = fc__equalUpdateStmt(fc_a, fc_b);
			break;
		case T_MergeStmt:
			fc_retval = fc__equalMergeStmt(fc_a, fc_b);
			break;
		case T_SelectStmt:
			fc_retval = fc__equalSelectStmt(fc_a, fc_b);
			break;
		case T_SetOperationStmt:
			fc_retval = fc__equalSetOperationStmt(fc_a, fc_b);
			break;
		case T_ReturnStmt:
			fc_retval = fc__equalReturnStmt(fc_a, fc_b);
			break;
		case T_PLAssignStmt:
			fc_retval = fc__equalPLAssignStmt(fc_a, fc_b);
			break;
		case T_AlterTableStmt:
			fc_retval = fc__equalAlterTableStmt(fc_a, fc_b);
			break;
		case T_AlterTableCmd:
			fc_retval = fc__equalAlterTableCmd(fc_a, fc_b);
			break;
		case T_AlterCollationStmt:
			fc_retval = fc__equalAlterCollationStmt(fc_a, fc_b);
			break;
		case T_AlterDomainStmt:
			fc_retval = fc__equalAlterDomainStmt(fc_a, fc_b);
			break;
		case T_GrantStmt:
			fc_retval = fc__equalGrantStmt(fc_a, fc_b);
			break;
		case T_GrantRoleStmt:
			fc_retval = fc__equalGrantRoleStmt(fc_a, fc_b);
			break;
		case T_AlterDefaultPrivilegesStmt:
			fc_retval = fc__equalAlterDefaultPrivilegesStmt(fc_a, fc_b);
			break;
		case T_DeclareCursorStmt:
			fc_retval = fc__equalDeclareCursorStmt(fc_a, fc_b);
			break;
		case T_ClosePortalStmt:
			fc_retval = fc__equalClosePortalStmt(fc_a, fc_b);
			break;
		case T_CallStmt:
			fc_retval = fc__equalCallStmt(fc_a, fc_b);
			break;
		case T_ClusterStmt:
			fc_retval = fc__equalClusterStmt(fc_a, fc_b);
			break;
		case T_CopyStmt:
			fc_retval = fc__equalCopyStmt(fc_a, fc_b);
			break;
		case T_CreateStmt:
			fc_retval = fc__equalCreateStmt(fc_a, fc_b);
			break;
		case T_TableLikeClause:
			fc_retval = fc__equalTableLikeClause(fc_a, fc_b);
			break;
		case T_DefineStmt:
			fc_retval = fc__equalDefineStmt(fc_a, fc_b);
			break;
		case T_DropStmt:
			fc_retval = fc__equalDropStmt(fc_a, fc_b);
			break;
		case T_TruncateStmt:
			fc_retval = fc__equalTruncateStmt(fc_a, fc_b);
			break;
		case T_CommentStmt:
			fc_retval = fc__equalCommentStmt(fc_a, fc_b);
			break;
		case T_SecLabelStmt:
			fc_retval = fc__equalSecLabelStmt(fc_a, fc_b);
			break;
		case T_FetchStmt:
			fc_retval = fc__equalFetchStmt(fc_a, fc_b);
			break;
		case T_IndexStmt:
			fc_retval = fc__equalIndexStmt(fc_a, fc_b);
			break;
		case T_CreateStatsStmt:
			fc_retval = fc__equalCreateStatsStmt(fc_a, fc_b);
			break;
		case T_AlterStatsStmt:
			fc_retval = fc__equalAlterStatsStmt(fc_a, fc_b);
			break;
		case T_CreateFunctionStmt:
			fc_retval = fc__equalCreateFunctionStmt(fc_a, fc_b);
			break;
		case T_FunctionParameter:
			fc_retval = fc__equalFunctionParameter(fc_a, fc_b);
			break;
		case T_AlterFunctionStmt:
			fc_retval = fc__equalAlterFunctionStmt(fc_a, fc_b);
			break;
		case T_DoStmt:
			fc_retval = fc__equalDoStmt(fc_a, fc_b);
			break;
		case T_RenameStmt:
			fc_retval = fc__equalRenameStmt(fc_a, fc_b);
			break;
		case T_AlterObjectDependsStmt:
			fc_retval = fc__equalAlterObjectDependsStmt(fc_a, fc_b);
			break;
		case T_AlterObjectSchemaStmt:
			fc_retval = fc__equalAlterObjectSchemaStmt(fc_a, fc_b);
			break;
		case T_AlterOwnerStmt:
			fc_retval = fc__equalAlterOwnerStmt(fc_a, fc_b);
			break;
		case T_AlterOperatorStmt:
			fc_retval = fc__equalAlterOperatorStmt(fc_a, fc_b);
			break;
		case T_AlterTypeStmt:
			fc_retval = fc__equalAlterTypeStmt(fc_a, fc_b);
			break;
		case T_RuleStmt:
			fc_retval = fc__equalRuleStmt(fc_a, fc_b);
			break;
		case T_NotifyStmt:
			fc_retval = fc__equalNotifyStmt(fc_a, fc_b);
			break;
		case T_ListenStmt:
			fc_retval = fc__equalListenStmt(fc_a, fc_b);
			break;
		case T_UnlistenStmt:
			fc_retval = fc__equalUnlistenStmt(fc_a, fc_b);
			break;
		case T_TransactionStmt:
			fc_retval = fc__equalTransactionStmt(fc_a, fc_b);
			break;
		case T_CompositeTypeStmt:
			fc_retval = fc__equalCompositeTypeStmt(fc_a, fc_b);
			break;
		case T_CreateEnumStmt:
			fc_retval = fc__equalCreateEnumStmt(fc_a, fc_b);
			break;
		case T_CreateRangeStmt:
			fc_retval = fc__equalCreateRangeStmt(fc_a, fc_b);
			break;
		case T_AlterEnumStmt:
			fc_retval = fc__equalAlterEnumStmt(fc_a, fc_b);
			break;
		case T_ViewStmt:
			fc_retval = fc__equalViewStmt(fc_a, fc_b);
			break;
		case T_LoadStmt:
			fc_retval = fc__equalLoadStmt(fc_a, fc_b);
			break;
		case T_CreateDomainStmt:
			fc_retval = fc__equalCreateDomainStmt(fc_a, fc_b);
			break;
		case T_CreateOpClassStmt:
			fc_retval = fc__equalCreateOpClassStmt(fc_a, fc_b);
			break;
		case T_CreateOpClassItem:
			fc_retval = fc__equalCreateOpClassItem(fc_a, fc_b);
			break;
		case T_CreateOpFamilyStmt:
			fc_retval = fc__equalCreateOpFamilyStmt(fc_a, fc_b);
			break;
		case T_AlterOpFamilyStmt:
			fc_retval = fc__equalAlterOpFamilyStmt(fc_a, fc_b);
			break;
		case T_CreatedbStmt:
			fc_retval = fc__equalCreatedbStmt(fc_a, fc_b);
			break;
		case T_AlterDatabaseStmt:
			fc_retval = fc__equalAlterDatabaseStmt(fc_a, fc_b);
			break;
		case T_AlterDatabaseRefreshCollStmt:
			fc_retval = fc__equalAlterDatabaseRefreshCollStmt(fc_a, fc_b);
			break;
		case T_AlterDatabaseSetStmt:
			fc_retval = fc__equalAlterDatabaseSetStmt(fc_a, fc_b);
			break;
		case T_DropdbStmt:
			fc_retval = fc__equalDropdbStmt(fc_a, fc_b);
			break;
		case T_VacuumStmt:
			fc_retval = fc__equalVacuumStmt(fc_a, fc_b);
			break;
		case T_VacuumRelation:
			fc_retval = fc__equalVacuumRelation(fc_a, fc_b);
			break;
		case T_ExplainStmt:
			fc_retval = fc__equalExplainStmt(fc_a, fc_b);
			break;
		case T_CreateTableAsStmt:
			fc_retval = fc__equalCreateTableAsStmt(fc_a, fc_b);
			break;
		case T_RefreshMatViewStmt:
			fc_retval = fc__equalRefreshMatViewStmt(fc_a, fc_b);
			break;
		case T_ReplicaIdentityStmt:
			fc_retval = fc__equalReplicaIdentityStmt(fc_a, fc_b);
			break;
		case T_AlterSystemStmt:
			fc_retval = fc__equalAlterSystemStmt(fc_a, fc_b);
			break;
		case T_CreateSeqStmt:
			fc_retval = fc__equalCreateSeqStmt(fc_a, fc_b);
			break;
		case T_AlterSeqStmt:
			fc_retval = fc__equalAlterSeqStmt(fc_a, fc_b);
			break;
		case T_VariableSetStmt:
			fc_retval = fc__equalVariableSetStmt(fc_a, fc_b);
			break;
		case T_VariableShowStmt:
			fc_retval = fc__equalVariableShowStmt(fc_a, fc_b);
			break;
		case T_DiscardStmt:
			fc_retval = fc__equalDiscardStmt(fc_a, fc_b);
			break;
		case T_CreateTableSpaceStmt:
			fc_retval = fc__equalCreateTableSpaceStmt(fc_a, fc_b);
			break;
		case T_DropTableSpaceStmt:
			fc_retval = fc__equalDropTableSpaceStmt(fc_a, fc_b);
			break;
		case T_AlterTableSpaceOptionsStmt:
			fc_retval = fc__equalAlterTableSpaceOptionsStmt(fc_a, fc_b);
			break;
		case T_AlterTableMoveAllStmt:
			fc_retval = fc__equalAlterTableMoveAllStmt(fc_a, fc_b);
			break;
		case T_CreateExtensionStmt:
			fc_retval = fc__equalCreateExtensionStmt(fc_a, fc_b);
			break;
		case T_AlterExtensionStmt:
			fc_retval = fc__equalAlterExtensionStmt(fc_a, fc_b);
			break;
		case T_AlterExtensionContentsStmt:
			fc_retval = fc__equalAlterExtensionContentsStmt(fc_a, fc_b);
			break;
		case T_CreateFdwStmt:
			fc_retval = fc__equalCreateFdwStmt(fc_a, fc_b);
			break;
		case T_AlterFdwStmt:
			fc_retval = fc__equalAlterFdwStmt(fc_a, fc_b);
			break;
		case T_CreateForeignServerStmt:
			fc_retval = fc__equalCreateForeignServerStmt(fc_a, fc_b);
			break;
		case T_AlterForeignServerStmt:
			fc_retval = fc__equalAlterForeignServerStmt(fc_a, fc_b);
			break;
		case T_CreateUserMappingStmt:
			fc_retval = fc__equalCreateUserMappingStmt(fc_a, fc_b);
			break;
		case T_AlterUserMappingStmt:
			fc_retval = fc__equalAlterUserMappingStmt(fc_a, fc_b);
			break;
		case T_DropUserMappingStmt:
			fc_retval = fc__equalDropUserMappingStmt(fc_a, fc_b);
			break;
		case T_CreateForeignTableStmt:
			fc_retval = fc__equalCreateForeignTableStmt(fc_a, fc_b);
			break;
		case T_ImportForeignSchemaStmt:
			fc_retval = fc__equalImportForeignSchemaStmt(fc_a, fc_b);
			break;
		case T_CreateTransformStmt:
			fc_retval = fc__equalCreateTransformStmt(fc_a, fc_b);
			break;
		case T_CreateAmStmt:
			fc_retval = fc__equalCreateAmStmt(fc_a, fc_b);
			break;
		case T_CreateTrigStmt:
			fc_retval = fc__equalCreateTrigStmt(fc_a, fc_b);
			break;
		case T_CreateEventTrigStmt:
			fc_retval = fc__equalCreateEventTrigStmt(fc_a, fc_b);
			break;
		case T_AlterEventTrigStmt:
			fc_retval = fc__equalAlterEventTrigStmt(fc_a, fc_b);
			break;
		case T_CreatePLangStmt:
			fc_retval = fc__equalCreatePLangStmt(fc_a, fc_b);
			break;
		case T_CreateRoleStmt:
			fc_retval = fc__equalCreateRoleStmt(fc_a, fc_b);
			break;
		case T_AlterRoleStmt:
			fc_retval = fc__equalAlterRoleStmt(fc_a, fc_b);
			break;
		case T_AlterRoleSetStmt:
			fc_retval = fc__equalAlterRoleSetStmt(fc_a, fc_b);
			break;
		case T_DropRoleStmt:
			fc_retval = fc__equalDropRoleStmt(fc_a, fc_b);
			break;
		case T_LockStmt:
			fc_retval = fc__equalLockStmt(fc_a, fc_b);
			break;
		case T_ConstraintsSetStmt:
			fc_retval = fc__equalConstraintsSetStmt(fc_a, fc_b);
			break;
		case T_ReindexStmt:
			fc_retval = fc__equalReindexStmt(fc_a, fc_b);
			break;
		case T_CheckPointStmt:
			fc_retval = true;
			break;
		case T_CreateSchemaStmt:
			fc_retval = fc__equalCreateSchemaStmt(fc_a, fc_b);
			break;
		case T_CreateConversionStmt:
			fc_retval = fc__equalCreateConversionStmt(fc_a, fc_b);
			break;
		case T_CreateCastStmt:
			fc_retval = fc__equalCreateCastStmt(fc_a, fc_b);
			break;
		case T_PrepareStmt:
			fc_retval = fc__equalPrepareStmt(fc_a, fc_b);
			break;
		case T_ExecuteStmt:
			fc_retval = fc__equalExecuteStmt(fc_a, fc_b);
			break;
		case T_DeallocateStmt:
			fc_retval = fc__equalDeallocateStmt(fc_a, fc_b);
			break;
		case T_DropOwnedStmt:
			fc_retval = fc__equalDropOwnedStmt(fc_a, fc_b);
			break;
		case T_ReassignOwnedStmt:
			fc_retval = fc__equalReassignOwnedStmt(fc_a, fc_b);
			break;
		case T_AlterTSDictionaryStmt:
			fc_retval = fc__equalAlterTSDictionaryStmt(fc_a, fc_b);
			break;
		case T_AlterTSConfigurationStmt:
			fc_retval = fc__equalAlterTSConfigurationStmt(fc_a, fc_b);
			break;
		case T_CreatePolicyStmt:
			fc_retval = fc__equalCreatePolicyStmt(fc_a, fc_b);
			break;
		case T_AlterPolicyStmt:
			fc_retval = fc__equalAlterPolicyStmt(fc_a, fc_b);
			break;
		case T_CreatePublicationStmt:
			fc_retval = fc__equalCreatePublicationStmt(fc_a, fc_b);
			break;
		case T_AlterPublicationStmt:
			fc_retval = fc__equalAlterPublicationStmt(fc_a, fc_b);
			break;
		case T_CreateSubscriptionStmt:
			fc_retval = fc__equalCreateSubscriptionStmt(fc_a, fc_b);
			break;
		case T_AlterSubscriptionStmt:
			fc_retval = fc__equalAlterSubscriptionStmt(fc_a, fc_b);
			break;
		case T_DropSubscriptionStmt:
			fc_retval = fc__equalDropSubscriptionStmt(fc_a, fc_b);
			break;
		case T_A_Expr:
			fc_retval = fc__equalA_Expr(fc_a, fc_b);
			break;
		case T_ColumnRef:
			fc_retval = fc__equalColumnRef(fc_a, fc_b);
			break;
		case T_ParamRef:
			fc_retval = fc__equalParamRef(fc_a, fc_b);
			break;
		case T_A_Const:
			fc_retval = fc__equalA_Const(fc_a, fc_b);
			break;
		case T_FuncCall:
			fc_retval = fc__equalFuncCall(fc_a, fc_b);
			break;
		case T_A_Star:
			fc_retval = fc__equalA_Star(fc_a, fc_b);
			break;
		case T_A_Indices:
			fc_retval = fc__equalA_Indices(fc_a, fc_b);
			break;
		case T_A_Indirection:
			fc_retval = fc__equalA_Indirection(fc_a, fc_b);
			break;
		case T_A_ArrayExpr:
			fc_retval = fc__equalA_ArrayExpr(fc_a, fc_b);
			break;
		case T_ResTarget:
			fc_retval = fc__equalResTarget(fc_a, fc_b);
			break;
		case T_MultiAssignRef:
			fc_retval = fc__equalMultiAssignRef(fc_a, fc_b);
			break;
		case T_TypeCast:
			fc_retval = fc__equalTypeCast(fc_a, fc_b);
			break;
		case T_CollateClause:
			fc_retval = fc__equalCollateClause(fc_a, fc_b);
			break;
		case T_SortBy:
			fc_retval = fc__equalSortBy(fc_a, fc_b);
			break;
		case T_WindowDef:
			fc_retval = fc__equalWindowDef(fc_a, fc_b);
			break;
		case T_RangeSubselect:
			fc_retval = fc__equalRangeSubselect(fc_a, fc_b);
			break;
		case T_RangeFunction:
			fc_retval = fc__equalRangeFunction(fc_a, fc_b);
			break;
		case T_RangeTableSample:
			fc_retval = fc__equalRangeTableSample(fc_a, fc_b);
			break;
		case T_RangeTableFunc:
			fc_retval = fc__equalRangeTableFunc(fc_a, fc_b);
			break;
		case T_RangeTableFuncCol:
			fc_retval = fc__equalRangeTableFuncCol(fc_a, fc_b);
			break;
		case T_TypeName:
			fc_retval = fc__equalTypeName(fc_a, fc_b);
			break;
		case T_IndexElem:
			fc_retval = fc__equalIndexElem(fc_a, fc_b);
			break;
		case T_StatsElem:
			fc_retval = fc__equalStatsElem(fc_a, fc_b);
			break;
		case T_ColumnDef:
			fc_retval = fc__equalColumnDef(fc_a, fc_b);
			break;
		case T_Constraint:
			fc_retval = fc__equalConstraint(fc_a, fc_b);
			break;
		case T_DefElem:
			fc_retval = fc__equalDefElem(fc_a, fc_b);
			break;
		case T_LockingClause:
			fc_retval = fc__equalLockingClause(fc_a, fc_b);
			break;
		case T_RangeTblEntry:
			fc_retval = fc__equalRangeTblEntry(fc_a, fc_b);
			break;
		case T_RangeTblFunction:
			fc_retval = fc__equalRangeTblFunction(fc_a, fc_b);
			break;
		case T_TableSampleClause:
			fc_retval = fc__equalTableSampleClause(fc_a, fc_b);
			break;
		case T_WithCheckOption:
			fc_retval = fc__equalWithCheckOption(fc_a, fc_b);
			break;
		case T_SortGroupClause:
			fc_retval = fc__equalSortGroupClause(fc_a, fc_b);
			break;
		case T_GroupingSet:
			fc_retval = fc__equalGroupingSet(fc_a, fc_b);
			break;
		case T_WindowClause:
			fc_retval = fc__equalWindowClause(fc_a, fc_b);
			break;
		case T_RowMarkClause:
			fc_retval = fc__equalRowMarkClause(fc_a, fc_b);
			break;
		case T_WithClause:
			fc_retval = fc__equalWithClause(fc_a, fc_b);
			break;
		case T_InferClause:
			fc_retval = fc__equalInferClause(fc_a, fc_b);
			break;
		case T_OnConflictClause:
			fc_retval = fc__equalOnConflictClause(fc_a, fc_b);
			break;
		case T_CTESearchClause:
			fc_retval = fc__equalCTESearchClause(fc_a, fc_b);
			break;
		case T_CTECycleClause:
			fc_retval = fc__equalCTECycleClause(fc_a, fc_b);
			break;
		case T_CommonTableExpr:
			fc_retval = fc__equalCommonTableExpr(fc_a, fc_b);
			break;
		case T_MergeWhenClause:
			fc_retval = fc__equalMergeWhenClause(fc_a, fc_b);
			break;
		case T_MergeAction:
			fc_retval = fc__equalMergeAction(fc_a, fc_b);
			break;
		case T_ObjectWithArgs:
			fc_retval = fc__equalObjectWithArgs(fc_a, fc_b);
			break;
		case T_AccessPriv:
			fc_retval = fc__equalAccessPriv(fc_a, fc_b);
			break;
		case T_XmlSerialize:
			fc_retval = fc__equalXmlSerialize(fc_a, fc_b);
			break;
		case T_RoleSpec:
			fc_retval = fc__equalRoleSpec(fc_a, fc_b);
			break;
		case T_TriggerTransition:
			fc_retval = fc__equalTriggerTransition(fc_a, fc_b);
			break;
		case T_PartitionElem:
			fc_retval = fc__equalPartitionElem(fc_a, fc_b);
			break;
		case T_PartitionSpec:
			fc_retval = fc__equalPartitionSpec(fc_a, fc_b);
			break;
		case T_PartitionBoundSpec:
			fc_retval = fc__equalPartitionBoundSpec(fc_a, fc_b);
			break;
		case T_PartitionRangeDatum:
			fc_retval = fc__equalPartitionRangeDatum(fc_a, fc_b);
			break;
		case T_PartitionCmd:
			fc_retval = fc__equalPartitionCmd(fc_a, fc_b);
			break;
		case T_PublicationObjSpec:
			fc_retval = fc__equalPublicationObject(fc_a, fc_b);
			break;
		case T_PublicationTable:
			fc_retval = fc__equalPublicationTable(fc_a, fc_b);
			break;

		default:
			elog(ERROR, "unrecognized node type: %d",
				 (int) nodeTag(fc_a));
			fc_retval = false;		/* 保持编译器安静 */
			break;
	}

	return fc_retval;
}
